I usually code in other languages (R, Python and Java), but recently started using C++. I've been solving problems on hackerrank.com, and specifically I bumped into this one:
https://www.hackerrank.com/challenges/variable-sized-arrays
Prior to this question, I had never gotten a Segmentation Fault error. I've tinkered with the code and discovered that the error only occurs when I attempt to print from the arr variable.
I wonder if someone could help me with this, and maybe provide a detailed explanation as to the precise error?
The code is as follows, but the issue is likely with int arr[100000][100000] = {-1}; and printf("%d\n", arr[iHat][jHat]); because I can printf both iHat and jHat themselves, but I am unable to use them to access integers in the arr array.
#include <iostream>
using namespace std;
int main(){
int n, q;
/*
*scan in:
*n array entries
*q quaries
*/
int arr[100000][100000] = {-1}; //initialize an array, larger than 10^5
scanf("%d %d\n", &n, &q); //n is size of array, q is # of quaries
for (int i = 0; i < n; ++i){ //loop through lines of input to populate array
int c, y = 0; //initialize to zero at the start of each line
while((c = getchar()) != '\n'){ //readline
if(c != ' '){ //pass spaces
arr[i][y] = c; //place integer into array
++y;
}
}
}
for (int i = 0; i < q; ++i){
int iHat, jHat = 0;
scanf("%d %d\n", &iHat, &jHat); //scan for coordinates
printf("%d\n", arr[iHat][jHat]); //Segmentation fault occurs here, why?
}
return 0;
}
Update
This question focused on memory management, and in particular the use of pointers. A functioning solution, resulting in no segmentation faults, is as follows:
#include <iostream>
using namespace std;
int main(){
int n, q;
/*
*scan in:
*n array entries
*q quaries
* format: %d %d
*/
scanf("%d %d\n", &n, &q);//n is size of array of arrays, q is # of quaries
int **arr = new int *[n]; //int** arr is a pointer of pointers of size n
for (int i = 0; i < n; ++i){//loop through lines of input to populate array
int k; //Always initialize variables in the narrowest scope possible!
scanf("%d", &k);//grab k, the number of ints in the line
arr[i] = new int[k];//create a 2nd dimension at entry i of size k
for (int j = 0; j < k; ++j){
scanf("%d", &arr[i][j]);//populate array
}
}
for (int i = 0; i < q; ++i){
int iHat, jHat = 0;
scanf("%d %d\n", &iHat, &jHat); //scan for query coordinates
printf("%d\n", arr[iHat][jHat]); //print results of query
}
return 0;
}
C++ gives you control of where you want to allocate memory. In your case, what you have found is that you allocated an array-of-array-of-int on the stack which exceeds the stack size. At some point, you access one of these elements which lies outside the bounds of the stack and also the program, which causes an access violation called a segmentation fault.
Since you mentioned being new to C++, it would help to understand these 3 areas of memory and how you would use each for your case:
Stack memory - space for temporary variables to automatically use without having to explicitly request. You will see undefined behavior if you exceed the stack size.
int main() {
int arr[100000][100000];
}
Heap memory - space for dynamically allocating space whenever explicitly requested using the operator "new". An "std::bad_alloc" exception will be thrown if the requested memory size exceeds what is available.
int main() {
int **arr = new int *[100000];
for (std::size_t i = 0; i < 100000; ++i) {
arr[i] = new int[100000];
}
}
Static memory - space allocated for static objects before main runs. You will get a compiler error if the array dimensions are too large.
int arr[100000][100000];
int main() {
...
}
That's 40 GB!
Even if you have that much RAM in the machine, it is surely not allocated as stack space.
If you do have that much memory you can move the arr to the global area before main. That way it will not be on the stack.
If you don't have 40+ GB available, you might have to rethink the solution. :-) Perhaps do the calculations in smaller segments?
Here are a few thoughts
1) You are trying to allocate 100,000 x 100,000 bytes, which equal 10,000,000,000 bytes (~10GB) on the stack. The default stack size is about 8MB on 32-bit linux. Even if the stack size is larger it won't be 10GB.
2) The name of the exercise you were working on is "Variable Sized Array" The line you entered,int arr[100000][100000] is a fixed size array. You should be using keyword new to dynamically create the array.
3) The reason for the Segmentation Fault error is because your print statement is attempting to access memory outside of the Virtual Memory space allowed for a stack size.
[Suggestion]
1) trying doing some exercises where you allocate and clean up dynamic memory using new and delete. Also in C++ allocating and deleting arrays is done differently than just a single data structure.
Cheers
Are you trying to do this?
#include <iostream>
using namespace std;
int main(){
int n, q;
const int length = 100;
int arr[length][length] = { -1 };
cout << "Enter length of 2d array" << endl;
cin>>n>>q;
cout << "Fill the array" << endl;
for (int i = 0; i < n; ++i) {
for(int y=0;y<q;y++){
int f;
cin >> f;
arr[i][y]=f;
}
}
int iHat;
int jHat;
cout << "Enter coordinates" << endl;
cin>>iHat>>jHat;
cout<<arr[iHat][jHat];
return 0;
}
P.S i decreased array size, becouse 100000 x 100000 this is lot of gigabytes and it says array is too large
Related
Currently, C++ only allows declaring arrays with length as integers. Is there any way to get around it? I am trying to create a program that generates an array that can potentially reach thousands or even millions in length depending on input, but array declaration limiting to integer-only length is holding me back.
Comment Basically, supposing that I want to create a 2d array with 5 rows and 500,000 columns, I get a segmentation fault.
The prototype for std::array is
template<class T, std::size_t N> struct array;
According to https://en.cppreference.com/w/cpp/types/size_t,
std::size_t can store the maximum size of a theoretically possible
object of any type (including array). A type whose size cannot be
represented by std::size_t is ill-formed (since C++14)
(emphasis mine)
So C++, by definition, cannot express the concept of an object whose size is larger than a std::size_t.
Fortunately, on most platforms std::size_t is going to be 32 bits at a minimum, meaning it can reach not only millions but billions. And if you're on a platform where it's smaller than that then presumably your hardware isn't physically capable of storing larger objects anyway.
UPDATE: In the comments you add
Sorry, I ought to have been more specific. Basically, supposing that I
want to create a 2d array with 5 rows and 500,000 columns, I get a
segmentation fault.
If the problem here were a limitation of the language, you would get a compiler error, not a runtime error.
Since you're getting a runtime error, the problem is with your platform, not the language. In this particular case, the "problem" is that it doesn't give you enough stack space to support multi-megabyte objects in a stack frame. (This is a pretty sensible limitation, if you ask me.) Instead, you'll want to allocate your data on the heap.
I could hand you some code that would just make your problem go away for now, but what you really need to do is read about the stack and heap and understand what they are and how to use them.
#include <iostream>
int main() {
int n = 0;
std::cin >> n;
int *arr = new int[n]; // dynamic declaration of variable length array
for(int i = 0; i < n; ++i)
std::cin >> arr[i]; // read array elements
return 0;
}
EDIT: For 2d array
#include <iostream>
int main() {
int **arr;
int r, c;
std::cin >> r >> c;
// Create an array of row heads
arr = new int *[r];
// Create an 2d array
for (int i = 0; i < r; ++i) arr[i] = new int[c];
// read input in 2d array
for (int i = 0; i < r; ++i)
for (int j = 0; j < c; ++j) std::cin >> arr[i][j];
// print 2d array
for (int i = 0; i < r; ++i)
for (int j = 0; j < c; ++j) std::cout << arr[i][j] << ' ';
return 0;
}
std::vectoris a better choice. You only need push_back or emplace_backto add element into it.
More details:
http://www.cplusplus.com/reference/vector/vector/
Can't resolve this problem - my compiler allways tells me that I have some troubles with the free(pointer) function. So I'm not sure about the working of my pointers but debugging has shown that actually everything works well. Only the free function could't free the memory.
#include <stdio.h> //Bibliothek für input/output.
#include <stdlib.h> //For malloc
#include <math.h> //Bibliothek für matchematische Operationen.
#include <iostream> //Bibliothek für in/output in C++.
#include <stdbool.h> //Bibliothek für boolean
//Prototypes
int* readNumbers(int size);
int sumUpNumbers(int* sumpointer, int size);
//Main function
int main()
{
int arraySize; //Size of the malloc-array
int* pointer; //pointer for storing of the malloc-address
int total; //variable for the sumUpNumbers function
pointer = NULL; //point on zero
//inform the user before getting a number from him
std::cout << "Please give the size of array:" << std::endl;
fflush(stdout); //free the output window
//get a number for the size of array
scanf("%d", &arraySize);
//call the readNumbers function and store the first address of
//the malloc-array in pointer
pointer = readNumbers(arraySize);
//call the sumUpNumbers function and store the number in total
total = sumUpNumbers(pointer, arraySize);
fflush(stdout); //free the output window
//show the number from total
printf("\n total of the array:%d", total);
//call the free function for making the memory of
//the malloc-array free again
free(pointer);
fflush(stdin); //free the keyboard buffer
getchar(); //wait for a feedback from user
return 0; //return 0 to the machine in case if everything works well
}
//This function has a pointer extension because we want to work with the
//array outside of this function. We give the function a size of the array
//we want to build. The function builds an array and fills it with numbers
//and than gives us back the first address of the array.
int* readNumbers(int size)
{
int* array; //pointer for creating of malloc-array
int i; //counter
//pointer for storing of the first address of the array
int* helpPointer;
array = NULL; //set the pointers
helpPointer = NULL; // on zero
//create the array
array = (int *) malloc(size * sizeof(int));
//check the value of the array to be sure that we have created
//the array without errors
if(array != NULL)
{
//store the first address of the malloc-pointer
helpPointer = array;
//give some value to all the parts of array
for(i=0; i<=size; i++)
{
//inform the user
printf("\n give the %d. nummber of the array:\n", i+1);
fflush(stdout); //free the output window
//read the value
scanf("%d", array+i);
}
return helpPointer; //return the first address
}
//if something went wrong by creating of the array, do:
else
{
//tell the user, what we computer does't have enough memory
std::cout << "There is no place for saving the data in mamory";
return 0; //return with failure
}
}
//The input of this function is a pointer with the address of the malloc-array
//from the readNumbers and the size of this array. The function adds all the numbers
//from the array and gives us the result of the additation back.
int sumUpNumbers(int* sumpointer, int size)
{
int sum; //variable for storing of total value
int i; //counter
sum = 0; //set the sum on zero before work with it
//count all the values from the array
for(i=0; i<=size; i++)
{
//count one number after another
sum = sum + *(sumpointer+i);
}
return sum; //return the total value
}
The limits of your for loops are wrong. You are writing into one position over the end of your array, which might corrupt the memory so that later the program fails. Change the for loops to:
for(i=0; i<size; i++)
In the readNumbers function you have:
for(i=0; i<=size; i++)
but the array is only size elements long, so just change <= to <:
for(i=0; i < size; i++)
You have the same problem in the sumUpNumbers function. But this will most likely just result in an incorrect sum although it is technically undefined behaviour.
Your code has few issues:
fflush(stdin) is a generator of undefined behavior.
two incorrect counters: if size is size, you must count for(i = 0; i < size; i++)
Your int* readNumbers(int size) returns int instead of int* if array is NULL.
strange mixing of C and C++ for no obvious reason to using cin and cout
Apart from having written three obvious mistakes (1) and (2) and (3), you also push yourself to use a C++ compiler (4) for compiling something, 99% of which is plain C code. Why?
In case you replace cin and cout with appropriate scanf() and printf() calls, you get rid of C++. So you can use a C compiler. In that case make sure to also modify malloc call in order to conform the C standard:
array = malloc(size * sizeof(int)); //no result casting!
Then you get 100% C code which is easier to read, study and debug.
Hey everyone I am relearning C++ by doing some hacker rank challenges and am getting a segment fault error. The program should take in the dimensions for the matrix and compute both diagonals, then add them together. I am pretty sure the error is in how the 2d array is passed to the computeMainDiagonal and computeSecondaryDiagonal functions. Thanks for the help !
int ComputeMatrixMainDiagonal(int matrixDimensions, int* matrix){
int rowIndent = 0;
int diagonalValue;
for(int i = 0;i < matrixDimensions;i++){
diagonalValue =+ (&matrix)[i][rowIndent];
rowIndent++;
}
return diagonalValue;
}
int ComputeMatrixSecondaryDiagonal(int matrixDimensions, int* matrix){
int rowIndent = matrixDimensions;
int diagonalValue;
for(int i = matrixDimensions;i > 0;i--){
diagonalValue =+ (&matrix)[i][rowIndent];
rowIndent--;
}
return diagonalValue;
}
int main() {
int matrixDimension;
int differenceAcrossSumsOfDiagonal;
int matrixMainDiagonal;
int matrixSecondaryDiagonal;
int * matrixPointer;
cin >> matrixDimension; //get matrix dimensions
int matrix[matrixDimension][matrixDimension]; //declare new matrix
for(int index = 0; index < matrixDimension;index++ ){ //populate matrix
for(int i = 0; i < matrixDimension;i++){
cin >> matrix[index][i];
}
}
matrixMainDiagonal = ComputeMatrixMainDiagonal(matrixDimension,&matrix[matrixDimension][matrixDimension]);
matrixSecondaryDiagonal = ComputeMatrixSecondaryDiagonal(matrixDimension,&matrix[matrixDimension][matrixDimension]);
differenceAcrossSumsOfDiagonal = (matrixMainDiagonal + matrixSecondaryDiagonal);
cout << differenceAcrossSumsOfDiagonal;
return 0;
}
Your segmentation fault likely occurs because &matrix[matrixDimension][matrixDimension] does not mean what you think it means. Your question title suggests that you think this is a way to pass the array by value (though why you would want to do so escapes me), but pass-by-value vs. pass-by-reference is a matter of how the function is declared, not of how it is called.
The expression &matrix[matrixDimension][matrixDimension] would be the address of the matrixDimensionth element of the matrixDimensionth row of the matrix. This is outside the bounds of the matrix, as the maximum index for an array is one less than the array dimension. Even if you wrote &matrix[matrixDimension - 1][matrixDimension - 1], however, it would not be what you want. You want the address of the first element of the array, which is &matrix[0][0] or simply matrix, though these are inequivalent on account of having different type (corresponding to different senses of what the elements of matrix are).
I am quite new to programming,so I really need help. I need to wrtie a function which produce 2d arrays with random values. here is my code:
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
float randArray(int row, int column);
int main()
{
int r = 10, c = 8;
float fckMmd = randArray(r,c);
///printing the array:
for (int row=0; row<r; row++){
for (int column=0; column<c; column++){
cout << fckMmd[row][column] << " ";
}
cout << endl;
}
}
float randArray(int row, int column){
srand(time(NULL));
float *randArr;
randArr = new int [row][column];
for(int k=0; k<row; k++){
for(int kk=0; kk<column; kk++){
randArr[k][kk] = rand();
}
}
return randArr;
}
But I get the error mentioned above. Where is the problem? help me please
randArr is a float * but you try to allocate a 2d array in it. A 2d array is not the same thing as a pointer. Your function only returns 1 float as well. I suggest you use vectors (also so you don't leak memory). Furthermore you should only call srand ONCE, not every time, and be aware rand() returns an integer, not a floating point value.
std::vector<std::vector<float>> randArray(int row, int column)
{
std::vector<std::vector<float>> randArr(row);
for (auto& v : randArr)
{
v.resize(column);
}
for(int k=0; k<row; k++)
{
for(int kk=0; kk<column; kk++)
{
randArr[k][kk] = static_cast<float>(rand());
}
}
return randArr;
}
It's because fckMmd is only a float and not a pointer or array.
First:
float *randArr;
declares a pointer to float. You then do
randArr = new int [row][column];
which allocates memory for a 2D array of ints (incompatible types, technically you allocate memory for a pointer to arrays of type int[column]), hence the error.
You're better using a std::vector instead, or, if you want a manually-managed dynamically allocated 2D array, use float **randArr; instead, and allocate
float** randArr;
randArr = new float* [rows];
for(int i = 0; i < row; ++i)
randArr[i] = new float[col];
or
float (*randArr)[col]; // pointer to array float[col]
randArr = new float[row][col];
Other issues: most of the time, srand must be used only once in the program. It is a good idea to call it in main() and not bury it into a function, since you may end up calling the function multiple times.
Last issue: if you want speed, you're better off using a single flat array (or std::vector) and map from 2D to 1D and vice versa, since your data will be guaranteed to be contiguous and you'll have very few cache misses.
I'm trying to create a dynamic array or what should you call that, using pointer, but when I try to cout the length of the array after setting the elements, it gives me 0. I'm not sure what I'm doing wrong here.
Here's the code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
int *p = NULL;
int kek = 0;
cin >> kek;
p = new int[kek];
for (int i = 0; i < kek; i++)
{
p[i] = 0;
}
int sizeOfArray = sizeof(p) / 8;
cout << sizeOfArray << endl;
delete[] p;
}
Better use the stl vector, this have the size() method
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> p;
int kek = 0;
cin >> kek;
p.resize(kek);
for (int i = 0; i < kek; i++)
{
p[i] = 0;
}
int sizeOfArray = p.size();
cout << sizeOfArray << endl;
p.clear();
return 0;
}
You are just taking the size of the pointer.
But just use std::vector
You can't use sizeof() to determine the size of a dynamically allocated array because the size can't be determined at compile time, and therefore is not stored anywhere.
When you have a statically allocated array like:
int numbers[40];
The compiler is able to figure out that the size of the block of memory called numbers is 40 items * 8 bytes each = 320 bytes, and determine that a statement like sizeof(numbers) is equivalent to 320, and do the proper substitutions.
But when you have something like
int *numbers = new int[n];
numbers is defined explicitly as a pointer to some memory, and when you do sizeof(numbers), it'll try to evaluate the size of the pointer, which will be 4 or 8 bytes depending on the compiler and platform you're on.
Again, numbers is a pointer, pointing to the first item in a block of memory. There's no easy way to tell which one of the blocks of memory in the computer it's pointing to, and how big the block is in bytes
So that means you'll have to keep track of the size of the array yourself.
You already have the variable kek, so size in bytes should be kek * sizeof(int)
Or like the others have said, you can also use a vector to keep track of the length for you:
vector<int> numbers;
int sizeInBytes = numbers.size() * sizeof(int);
It is not possible to determine the length of a new[]ed array in C++ from a pointer returned by new[]. So, your attempt to "to cout the length" does not really do that. sizeof does not do that and will not help you with that.
The only way to "cout" the size of a new[]ed array is to remember that size and manually carry it from the point where you allocated the array to the point where you need to "cout" the size. If you somehow lose knowledge of that size along the way, you will never be able to restore it.
In your case the size is kek. This is what you "cout".