I am trying to de-reference the 2D array inside the function islandPerimeter.
But I cannot understand why I am getting segfault for this.
Can someone point out what exactly I am doing wrong?
update:
So this was a part of a problem from leetcode I was trying to solve.I now understand it is not 2D array but a pointer. I am still confused over the int**. can someone explain it?
#include <stdio.h>
int islandPerimeter(int** grid, int gridSize, int gridColSize)
{
int perimeter=0,points=4,i=0;
for(int row=0;row<gridSize;++row)
{
for(int col=0;col<gridColSize;++col)
{
printf("%d ",grid[row][col]);
}
}
return perimeter;
}
int main()
{
int arr[4][5] = {{8,1,0,0,0},
{1,1,1,0,0},
{0,1,0,0,0},
{1,1,0,0,0}};
islandPerimeter(arr,4,5);
return 0;
}
A Pointer to Array
An array is a distinct type in C. It is a sequential collections of elements of a given type. In C a 2D array is actually an array of 1D arrays. In your case, you have an array [4] of int [5] (e.g. 4 - 5-elements arrays of int commonly called a 2D array of int)
Where new programmers normally get confused is how an array is treated on access. When an array is accessed, it is converted to a pointer to the first element. C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3) (pay attention to the 4 exceptions)
In the case of a 1D array, that is simple, the array is converted to a pointer to the first element of the array (the pointer is simply int*). In the case of a 2D array, the same holds true, the array is converted to a pointer to the first element -- but that first element is a 1D array of 5-int. (the pointer is a pointer-to-array of int [5], formally int (*)[5])
You can pass the 2D array (in your case) as a parameter of either int grid[4][5], int grid[][5], or to reflect that the array is converted to a pointer to the first element, int (*grid)[5]. The key is you must always provide the number of elements in the final dimension for your array (with additional '*' allowed for circumstances not relevant here) The 5 (or number of elements) must be an integer constant which is known at compile-time unless using a Variable Length Array (VLA), which are the topic for a separate discussion.
The same rule that on access an array is converted to a pointer to its first element applies to each dimension in your array, be it a 2D array or a 6D array. C11 Standard - 6.5.2.1 Array subscripting(p3)
Additionally, know the difference between a pointer-to-array (e.g. int (*grid)[5]) and an array-of-pointers (e.g. int *grid[5]). The parenthesis are required due to C Operator Precedence, the [..] has higher precedence than '*' in this case, so to require that *grid (in int *grid[5]) be evaluated as a pointer (instead of as an array grid[5]) you enclose it is parenthesis (*grid).
Thus resulting in a pointer-to-array of int [5], (int (*grid)[5]) instead of an array-of-pointers to int (5 of them) with int *grid[5].
A Pointer to Pointer
Contrast that with a pointer-to-pointer (e.g. int **, commonly called a double-pointer). You have two-levels of indirection represented by the two **. The pointer itself is a single-pointer -- to what? (another pointer, not to an array). You will generally use a double-pointer by first allocating a block of memory to hold some number of pointers, such as when you are dynamically allocating for an unknown number of allocated objects. This can be an unknown number of rows of an unknown number of columns of int or it can be an unknown number of strings, or a unknown number of structs, etc.. The key is your first level of indirection points to memory containing pointers.
Then for each of the available pointers you can allocate a block (e.g. in your case to hold 5 int and then assign the starting address for that block of memory to your first available pointer). You continue allocating for your columns (or strings or structs) and assigning the beginning address to each of your available pointers in sequence. When done, you can access the individual elements in your allocated collection using the same indexing you would for a 2D array. The difference between such a collection and a 2D array of arrays -- is the memory pointed to by each pointer need not be sequential in memory.
Telling Them Apart
The key to knowing which to use is to ask "What does my pointer point to?" Does it point to a pointer? Or, does it point to an array? If it points to another pointer, then you have a pointer-to-pointer. If the thing pointed to is an array, then you have a pointer-to-array. With that, you know what you need as a parameter.
Why the SegFault with int**
Type controls pointer arithmetic. Recall above, int** is a pointer-to-pointer, so how big is a pointer? (sizeof (a_pointer) - usually 8-bytes on x86_64, or 4-bytes on x86). So grid[1][0] is only one-pointer (8-bytes) away from grid[0][0]. What about the pointer-to-array? Each increment in the first index is a sizeof (int[5]) apart from the first. So in the case of a 4x5 array grid[1][0] is 5 * sizeof(int) (20-bytes) apart from grid[0][0].
So when attempting to access your array of arrays, using int**, beginning with grid[1][3] (or grid[1][4] on a 32-bit box) you are reading one-past the end of the 1st row of values. (you have offset by 8-bytes (one-pointer 8-bytes - skipping 2-int), placing you just before the 3rd integer in the 1st row, then offset 3 more integers placing you at what would be grid[0][5] one past the last value in the 1st row grid[0][4]. (this compounds with each row increment) The result is undefined and anything can happen.
When you pass the appropriate pointer-to-array, each increment of the row-index offsets by 20-bytes, placing you at the beginning of the next 1D array of values so iterating over each column remains within the bounds of that 1D array.
Think through it, and if you have further questions, just let me know and I'm happy to help further.
int** grid is a pointer to pointer to int. It lacks information of the array width.
With C99 or C11 onwards with optional variable length arrays:
// int islandPerimeter(int** grid, int gridSize, int gridColSize)
int islandPerimeter(int gridSize, int gridColSize, int grid[gridSize][gridColSize]) {
int perimeter=0;
for(int row=0;row<gridSize;++row) {
for(int col=0;col<gridColSize;++col) {
printf("%d ",grid[row][col]);
}
}
return perimeter;
}
Call with
islandPerimeter(4, 5, arr);
Try this
int islandPerimeter(int* grid, int gridSize, int gridColSize) {
int perimeter = 0, points = 4, i = 0;
for(int row=0; row < gridSize; ++row) {
for(int col = 0; col < gridColSize; ++col) {
printf("%d ",grid[row*gridColSize + col]);
}
}
return perimeter;
}
You will have to change the call to
islandPerimeter((int *)grid, 4, 5);
Let's say you wanted to leave your function as-is and instead change how the 2D array was initialized in main(or any other calling function). This is also what you would have to do if the array data was entered by a user or loaded from a file at runtime, so it's useful to know:
int main(void) {
const int ROWS = 4; //these don't have to be const;
const int COLS = 5;
const int data[20] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
int** pointer_arr = malloc(ROWS * sizeof(int*)); //allocate space for each ptr
//error check
if (pointer_arr == NULL) {
printf("Unsuccessful ptr-ptrarray allocation attempt\n");
exit(0);
}
for (int i = 0; i < ROWS; ++i) {
pointer_arr[i] = malloc(COLS * sizeof(int)); //allocate space for each int
//error check with alternative indexing syntax (same as pointer_arr[i])
if (*(pointer_arr + i) == NULL) {
printf("Unsuccessful ptr-intarray allocation attempt\n");
exit(0);
}
}
//load each allocated int address space with an int from data:
for (int i = 0; i < ROWS ; ++i) {
for (int j = 0; j < COLS; ++j) {
pointer_arr[i][j] = data[ROWS * i + j];
}
}
//Now you can call your unaltered function and it will perform as expected:
islandperimeter(pointer_arr, ROWS, COLS);
return 0;
}
Under normal conditions (when the program doesn't terminate at once) note that you would then have to manually free all that allocated memory, or suffer a memory leak.
Related
I have a 1d buffer which i have to re-organize to be accessed as a 2d array. I have pasted my code below:
#include <stdlib.h>
#include <stdio.h>
void alloc(int ** buf, int r, int c)
{
int **temp=buf;
for(int i=0; i<r; i++)
buf[i]=(int *)temp+i*c;
}
void main()
{
int *buffer=(int *)malloc(sizeof(int)*100);
int **p = (int**) buffer;
alloc(p, 4, 4);
//for(int i=0;i<r;i++)
//for(int j=0;j<c;j++)
// printf("\n %p",&p[i][j]);
p[0][3]=10;
p[2][3]=10;
p[3][2]=10; //fails here
printf("\n %d", p[2][3]);
}
The code is crashing when i make the assignment.
I have ran the code for different test cases. I have observed that the code crashes when there is an assignment to p[0][x] followed by assignment to p[x][anything] with the code crashing at the second assignment. This crash is seen only when the first index of the first assignment is 0 and for no other indices with the crash happening at the second assignment having the first index equal to the second index of the first assignment.
For example, in the above code crash happens at p[3][2] after p[0][3] has been executed. If i change the first assignment to p[0][2] then crash would happen at p[2][3]( or p[2][anything] for that matter).
I have checked the memory pointed to by p, by uncommenting the double for loop, and it seems to be fine. I was suspecting writing at illegal memory locations but that has been ruled out by the above observation.
The problem is that your 2D array is actually an array of pointers to arrays. That means you need to have space for the pointers. At the moment you have your pointers in positions 0-3 in the array, but p[0] is also pointing to position 0. When you write to 'p[0,3]' you are overwriting p[3].
One (tempting) way to fix it is to allow the pointers room at the start of the array. So you could change your alloc method to allow for some space at the front. Something like:
buf[i] = (int *)(temp+r) + i*c;
Note the +r adding to the temp. It needs to be added to temp before it is cast as you can't assume int and int * are the same type.
I would not recommend this method as you still have to remember to allocate extra space in your original malloc to account for the array of pointers. It also means you aren't just converting a 1D array to a 2D array.
Another option would be to allocate your array as an array of pointers to individually allocated arrays. This is the normal way to allocate 2D arrays. However this will not result in a contiguous array of data as you have in your 1D array.
Half way between these two options, you could allocate an extra array of pointers to hold the pointers you need, and then point them to the data. Change your alloc to something like:
int **alloc(int * buf, int r, int c)
{
int **temp = (int **)malloc(sizeof (int *)* r);
for (int i = 0; i<r; i++)
temp[i] = buf + i*c;
return temp;
}
then you call it like:
int **p = alloc(buffer, 4, 4);
you also need to free up the extra buffer.
This way your data and the pointers you need to access it are kept separate and you can keep your original 1D data contiguous.
Note that you don't need to cast the result of malloc in c, in fact some say that you shouldn't.
Also note that this method removes all of the requirement for casting pointers, anything that removes the need for a cast is a good thing.
I think that your fundamental problem is a misconception about 2D arrays in C (Your code is C, not C++).
A 2D array is a consecutive memory space , and the size of the inner array must be known in advance. So you basically cannot convert a 1D array into a 2D array unless the size of the inner array is known at compile time. If it is known, you can do something like
int *buffer=(int *)malloc(sizeof(int)*100);
typedef int FourInts[4];
FourInts *p = (FourInts *)buffer;
And you don't need an alloc function, the data is already aligned correctly.
If you don't know the size of the inner array in advance, you can define and allocate an array of arrays, pointing into the 1D buffer. Code for that:
int ** alloc(int * buf, int r, int c)
{
int **array2d = (int **) malloc(r*sizeof(int *));
for(int i=0; i<r; i++)
array2d[i] = buf+i*c;
return array2d;
}
void _tmain()
{
int *buffer=(int *)malloc(sizeof(int)*100);
int **p = alloc(buffer,4,4);
p[0][3]=10;
p[2][3]=10;
p[3][2]=10; //fails here
printf("\n %d", p[2][3]);
free(buffer);
free(p);
}
But it would have been easier to simply build an array of arrays without using the buffer. If you could use C++ instead of C, then everything could be easier.
If you already have a 1D block of data, the way to make it accessible as a 2D array is to create an array of pointers - one for each row. You point the first one to the start of the block, the next one is offset by the number of columns, etc.
int **b;
b = malloc(numrows*sizeof(int*));
b[0]=temp; // assuming temp is 1D block
for(int ii=1; ii<numrows;ii++)
b[ii]=b[0]+ii*numcols;
Now you can access b[i][j] and it will point to your original data. As long as number of rows and columns are known at run time this allows you to pass variable length 2D arrays around. Remember that you have to free the vector of pointers as well as the main data block when you are done or you will get a memory leak.
You will find examples of this if you google nrutil.c - this is derived from the trick Numerical Recipes in C uses.
This function prototype should be:
void alloc(int *buf[][], int r, int c) //buf[][] <=> **buf, but clearer in this case
{
//*(buf[i]) =
...
}
If you want to work on the same array you have to pass a pointer to this 2D array (*[][]).
The way you do it now is just working on a copy, so when you return it's not modified.
You should also initialize your array correctly :
p = malloc(sizeof(int *[]) * nb of row);
for each row
p[row] = malloc(sizeof(int []) * nb of col);
When an array is passed as an argument , the compiler generates a pointer to the array's first element and that pointer is passed to the function rather than the full array, so my question is why we can print the values of the array when we print array[i]?
void FunctionApi(int array[])
{
int i;
for(i=0;i<8;i++)
{
printf("Value =%d\n",array[i]);
//I understand the reason behind the following two lines but not the above line.
//printf("noOfElementsInArray=%d\n",*array);
//*array++;
}
}
int main()
{
int array[8]={2,8,10,1,0,1,5,3};
int noOfElementsInArray;
noOfElementsInArray=sizeof(array)/sizeof(int);
printf("noOfElementsInArray=%d\n",noOfElementsInArray);
FunctionApi(array);
return 0;
}
Array's elements are stored together in consecutive locations. That is why knowing the address of the initial element is sufficient to know where the rest of the elements are.
The only trick is knowing how many elements the array has. This is not passed along with the array, so you need to pass it separately. It is not a concern for your program because you hard-coded it to eight, but in general if you pass an array as an argument, you also need to pass its size as a separate parameter:
void FunctionApi(int array[], size_t count) {
int i;
for(i=0;i<count;i++) {
printf("Value =%d\n",array[i]);
}
}
As far as the noOfElementsInArray=sizeof(array)/sizeof(int); calculation goes, this trick works only in the caller, where array is an array, not a pointer to the initial element of the array. At this location the compiler knows that the size of the array is eight times the size of an int, so dividing out the sizeof(int) gives you the number of elements in the array.
Because array[i] is syntactically equivalent to *(array + i)
When you pass the name of an array, this is pointer to the first element as well as the entire array. Hence, when you access different elements as array[i] you are accessing successive data equivalent to *(array + i).
In this toy code example:
int MAX = 5;
void fillArray(int** someArray, int* blah) {
int i;
for (i=0; i<MAX; i++)
(*someArray)[i] = blah[i]; // segfault happens here
}
int main() {
int someArray[MAX];
int blah[] = {1, 2, 3, 4, 5};
fillArray(&someArray, blah);
return 0;
}
... I want to fill the array someArray, and have the changes persist outside the function.
This is part of a very large homework assignment, and this question addresses the issue without allowing me to copy the solution. I am given a function signature that accepts an int** as a parameter, and I'm supposed to code the logic to fill that array. I was under the impression that dereferencing &someArray within the fillArray() function would give me the required array (a pointer to the first element), and that using bracketed array element access on that array would give me the necessary position that needs to be assigned. However, I cannot figure out why I'm getting a segfault.
Many thanks!
I want to fill the array someArray, and have the changes persist outside the function.
Just pass the array to the function as it decays to a pointer to the first element:
void fillArray(int* someArray, int* blah) {
int i;
for (i=0; i<MAX; i++)
someArray[i] = blah[i];
}
and invoked:
fillArray(someArray, blah);
The changes to the elements will be visible outside of the function.
If the actual code was to allocate an array within fillArray() then an int** would be required:
void fillArray(int** someArray, int* blah) {
int i;
*someArray = malloc(sizeof(int) * MAX);
if (*someArray)
{
for (i=0; i<MAX; i++) /* or memcpy() instead of loop */
(*someArray)[i] = blah[i];
}
}
and invoked:
int* someArray = NULL;
fillArray(&someArray, blah);
free(someArray);
When you create an array, such as int myArray[10][20], a guaranteed contiguous block of memory is allocated from the stack, and normal array arithmetic is used to find any given element in the array.
If you want to allocate that 3D "array" from the heap, you use malloc() and get some memory back. That memory is "dumb". It's just a chunk of memory, which should be thought of as a vector. None of the navigational logic attendant with an array comes with that, which means you must find another way to navigate your desired 3D array.
Since your call to malloc() returns a pointer, the first variable you need is a pointer to hold the vector of int* s you're going to need to hold some actual integer data IE:
int *pArray;
...but this still isn't the storage you want to store integers. What you have is an array of pointers, currently pointing to nothing. To get storage for your data, you need to call malloc() 10 times, with each malloc() allocating space for 20 integers on each call, whose return pointers will be stored in the *pArray vector of pointers. This means that
int *pArray
needs to be changed to
int **pArray
to correctly indicate that it is a pointer to the base of a vector of pointers.
The first dereferencing, *pArray[i], lands you somewhere in an array of int pointers, and the 2nd dereferencing, *p[i][j], lands you somewhere inside an array of ints, pointed to by an int pointer in pArray[i].
IE: you have a cloud of integer vectors scattered all over the heap, pointed to by an array of pointers keeping track of their locations. Not at all similar to Array[10][20] allocated statically from the stack, which is all contiguous storage, and doesn't have a single pointer in it anywhere.
As others have eluded to, the pointer-based heap method doesn't seem to have a lot going for it at first glance, but turns out to be massively superior.
1st, and foremost, you can free() or realloc() to resize heap memory whenever you want, and it doesn't go out of scope when the function returns. More importantly, experienced C coders arrange their functions to operate on vectors where possible, where 1 level of indirection is removed in the function call. Finally, for large arrays, relative to available memory, and especially on large, shared machines, the large chunks of contiguous memory are often not available, and are not friendly to other programs that need memory to operate. Code with large static arrays, allocated on the stack, are maintenance nightmares.
Here you can see that the table is just a shell collecting vector pointers returned from vector operations, where everything interesting happens at the vector level, or element level. In this particular case, the vector code in VecRand() is calloc()ing it's own storage and returning calloc()'s return pointer to TblRand(), but TblRand has the flexibility to allocate VecRand()'s storage as well, just by replacing the NULL argument to VecRand() with a call to calloc()
/*-------------------------------------------------------------------------------------*/
dbl **TblRand(dbl **TblPtr, int rows, int cols)
{
int i=0;
if ( NULL == TblPtr ){
if (NULL == (TblPtr=(dbl **)calloc(rows, sizeof(dbl*))))
printf("\nCalloc for pointer array in TblRand failed");
}
for (; i!=rows; i++){
TblPtr[i] = VecRand(NULL, cols);
}
return TblPtr;
}
/*-------------------------------------------------------------------------------------*/
dbl *VecRand(dbl *VecPtr, int cols)
{
if ( NULL == VecPtr ){
if (NULL == (VecPtr=(dbl *)calloc(cols, sizeof(dbl))))
printf("\nCalloc for random number vector in VecRand failed");
}
Randx = GenRand(VecPtr, cols, Randx);
return VecPtr;
}
/*--------------------------------------------------------------------------------------*/
static long GenRand(dbl *VecPtr, int cols, long RandSeed)
{
dbl r=0, Denom=2147483647.0;
while ( cols-- )
{
RandSeed= (314159269 * RandSeed) & 0x7FFFFFFF;
r = sqrt(-2.0 * log((dbl)(RandSeed/Denom)));
RandSeed= (314159269 * RandSeed) & 0x7FFFFFFF;
*VecPtr = r * sin(TWOPI * (dbl)(RandSeed/Denom));
VecPtr++;
}
return RandSeed;
}
There is no "array/pointer" equivalence, and arrays and pointers are very different. Never confuse them. someArray is an array. &someArray is a pointer to an array, and has type int (*)[MAX]. The function takes a pointer to a pointer, i.e. int **, which needs to point to a pointer variable somewhere in memory. There is no pointer variable anywhere in your code. What could it possibly point to?
An array value can implicitly degrade into a pointer rvalue for its first element in certain expressions. Something that requires an lvalue like taking the address (&) obviously does not work this way. Here are some differences between array types and pointer types:
Array types cannot be assigned or passed. Pointer types can
Pointer to array and pointer to pointer are different types
Array of arrays and array of pointers are different types
The sizeof of an array type is the length times the size of the component type; the sizeof of a pointer is just the size of a
pointer
I want to allocate a 2-D array in C at runtime. Now this can be achieved in the conventional manner like this:
int *matrix[rows]
for (row = 0; row < rows; ++row) {
matrix[row] = (int *)malloc(ncol*sizeof(int));
}
But I found another method, which does the same thing:
int (*p)[rows];
p=(int (*)[rows])malloc(rows*cols*sizeof(int));
Can anyone explain how the 2nd declaration works? Specifically, what is meant by (int (*)[rows])malloc? To the best of my knowledge, malloc is used like (int *)malloc(ncol*sizeof(int)) or (char *)malloc(ncol*sizeof(char)).
Here, you cast malloc's return value to the type pointer to array rows of int.
By the way, in C, the cast of a pointer to void to a pointer to object is not requiered, and even useless. You should not worry about these details. The following code works indeed as well.
#include <stdlib.h>
int (*p)[rows];
p = malloc(rows * cols * sizeof(int));
These are not equivalent, the first allocates an array of pointers to integers, the second allocates an array of integers and returns a pointer to it, you just allocate several next to each other therefore allowing a second dimension to the 'array'.
A simpler version if you don't need the array after the end of the function would be:
int matrix[rows][cols];
When declaring an array like this:
int array[][] = {
{1,2,3},
{4,5,6}};
I get an error saying: "Array type has incomplete element type"
What is going on??
With an N-dimensional array (N>0), you need to define the sizes of N-1 dimensions; only one dimension can be left for the compiler to determine, and it must be the first dimension.
You can write:
int d1[] = { ... };
int d2[][2] = { ... };
int d3[][2][3] = { ... };
Etc.
You need to specify all the dimensions except the highest. The reason is that the compiler is going to allocate one big block of memory, as opposed to one array of pointers pointing to their own little arrays. In other words,
int array[][3][4] = ...;
will allocate one contiguous region of memory of size 3*4*(however many 3x4 arrays you declare here). Thus when later on in your code, you write
array[1][2][3] = 69;
in order to find where in memory to write 69, it starts at address (array), then jumps forward 12*sizeof(int) to get to array[1], plus 2*4*sizeof(int) to get to array[1][2], plus 3*sizeof(int) to finally get to the start of array[1][2][3]. Compare this to writing, for example,
int ***array = new int**[n];
for(i=0; i<n; i++)
{
array[i] = new int * [3];
for(j=0; j<4; j++)
array[i][j] = new int[4];
}
(sorry if my syntax isn't exact...been awhile since I've had to code something like this in C). In this example, array points to a block of code n*sizeof(int**) bytes long. Each element of this array points to another array of size 3*sizeof(int*) bytes long. Each element of these arrays points to another array of size 4*sizeof(int) bytes long. In this case, instead of calculating that array[1][2][3] is at address (array + something), it would need to follow a few different pointers in memory before finding where to write 69.
You have to tell it at least all the dimensions except the largest.
ie in your case
int array[][3] = {
{1,2,3},
{4,5,6}};