Crash while re-organizing 1d buffer as 2d array - c

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);

Related

2D array seg fault in C

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.

Compare content 2D pointers C

I have a pointer pointing to a 2D array of ints with dimensions [N][M] with M even. I define it allocating the memory as follows:
//alocate the memory of indxs pointer containing the indexs of each matrix element
int **indxs;
indxs = (int**) malloc(N*sizeof(int *));
for(i = 0; i<N; i++){
indxs[i] = (int *) malloc(M*sizeof(int));
}
Once filled I want to compare for each row (i_N) if the first half of the elements indxs[i_N][:M/2] is equal to the second half of the elements indxs[i_N][M/2:]. This [:M/2] is Python notation, I don't know how to do it in C, Any suggestion?. I have read in another post that for comparing the content of two pointers you have to dereference them first:
int *a = something;
int *b = something;
*a==*b
But how can this be done in my case?
First of all, this is not a 2D array but a lookup-table.
You can compare rows in your lookup-table like this:
#include <string.h>
if( memcmp( &indxs[i_N][0],
&indxs[i_N][M/2],
(M/2)*sizeof(indxs[0][0])) == 0 )
{
puts("equal");
}
This works fine since each "row" is pointing at a real array. An array = something that has memory cells allocated in adjacent memory.
However, since you don't have a 2D array, you wouldn't be able to do this on "columns", because all your row allocations are segmented all over the heap. For example, memcmp(indxs[0], indxs[n/2], (n/2)*sizeof(indxs[0][0])) would crash and burn. Solve this by using a 2D array instead.
Once filled I want to compare for each row (i_N) if the first half of the elements indxs[i_N][:M/2] is equal to the second half of the elements indxs[i_N][M/2:]. This [:M/2] is Python notation, I don't know how to do it in C
You can use memcmp, which in this case may look like this:
memcmp( indxs[i_N][0], indxs[i_N][M/2], (M/2)*sizeof( int ) )
Note memcmp returns 0 if equal. Check out memcpy prototype:
#include <string.h>
int memcmp(const void *s1, const void *s2, size_t n);
Note also, you should get rid of the cast for malloc:
indxs = malloc(N*sizeof(int *));

How to return a char** in C

I've been trying for a while now and I can not seem to get this working:
char** fetch (char *lat, char*lon){
char emps[10][50];
//char** array = emps;
int cnt = -1;
while (row = mysql_fetch_row(result))
{
char emp_det[3][20];
char temp_emp[50] = "";
for (int i = 0; i < 4; i++){
strcpy(emp_det[i], row[i]);
}
if ( (strncmp(emp_det[1], lat, 7) == 0) && (strncmp(emp_det[2], lon, 8) == 0) ) {
cnt++;
for (int i = 0; i < 4; i++){
strcat(temp_emp, emp_det[i]);
if(i < 3) {
strcat(temp_emp, " ");
}
}
strcpy(emps[cnt], temp_emp);
}
}
}
mysql_free_result(result);
mysql_close(connection);
return array;
Yes, I know array = emps is commented out, but without it commented, it tells me that the pointer types are incompatible. This, in case I forgot to mention, is in a char** type function and I want it to return emps[10][50] or the next best thing. How can I go about doing that? Thank you!
An array expression of type T [N][M] does not decay to T ** - it decays to type T (*)[M] (pointer to M-element array).
Secondly, you're trying to return the address of an array that's local to the function; once the function exits, the emps array no longer exists, and any pointer to it becomes invalid.
You'd probably be better off passing the target array as a parameter to the function and have the function write to it, rather than creating a new array within the function and returning it. You could dynamically allocate the array, but then you're doing a memory management dance, and the best way to avoid problems with memory management is to avoid doing memory management.
So your function definition would look like
void fetch( char *lat, char *lon, char emps[][50], size_t rows ) { ... }
and your function call would look like
char my_emps[10][50];
...
fetch( &lat, &lon, my_emps, 10 );
What you're attempting won't work, even if you attempt to cast, because you'll be returning the address of a local variable. When the function returns, that variable goes out of scope and the memory it was using is no longer valid. Attempting to dereference that address will result in undefined behavior.
What you need is to use dynamic memory allocation to create the data structure you want to return:
char **emps;
emps = malloc(10 * sizeof(char *));
for (int i=0; i<10; i++) {
emps[i] = malloc(50);
}
....
return emps;
The calling function will need to free the memory created by this function. It also needs to know how many allocations were done so it knows how many times to call free.
If you found a way to cast char emps[10][50]; into a char * or char **
you wouldn't be able to properly map the data (dimensions, etc). multi-dimensional char arrays are not char **. They're just contiguous memory with index calculation. Better fit to a char * BTW
but the biggest problem would be that emps would go out of scope, and the auto memory would be reallocated to some other variable, destroying the data.
There's a way to do it, though, if your dimensions are really fixed:
You can create a function that takes a char[10][50] as an in/out parameter (you cannot return an array, not allowed by the compiler, you could return a struct containing an array, but that wouldn't be efficient)
Example:
void myfunc(char emp[10][50])
{
emp[4][5] = 'a'; // update emp in the function
}
int main()
{
char x[10][50];
myfunc(x);
// ...
}
The main program is responsible of the memory of x which is passed as modifiable to myfunc routine: it is safe and fast (no memory copy)
Good practice: define a type like this typedef char matrix10_50[10][50]; it makes declarations more logical.
The main drawback here is that dimensions are fixed. If you want to use myfunc for another dimension set, you have to copy/paste it or use macros to define both (like a poor man's template).
EDITa fine comment suggests that some compilers support variable array size.
So you could pass dimensions alongside your unconstrained array:
void myfunc(int rows, int cols, char emp[rows][cols])
Tested, works with gcc 4.9 (probably on earlier versions too) only on C code, not C++ and not in .cpp files containing plain C (but still beats cumbersome malloc/free calls)
In order to understand why you can't do that, you need to understand how matrices work in C.
A matrix, let's say your char emps[10][50] is a continuous block of storage capable of storing 10*50=500 chars (imagine an array of 500 elements). When you access emps[i][j], it accesses the element at index 50*i + j in that "array" (pick a piece of paper and a pen to understand why). The problem is that the 50 in that formula is the number of columns in the matrix, which is known at the compile time from the data type itself. When you have a char** the compiler has no way of knowing how to access a random element in the matrix.
A way of building the matrix such that it is a char** is to create an array of pointers to char and then allocate each of those pointers:
char **emps = malloc(10 * sizeof(char*)); // create an array of 10 pointers to char
for (int i = 0; i < 10; i++)
emps[i] = malloc(50 * sizeof(char)); // create 10 arrays of 50 chars each
The point is, you can't convert a matrix to a double pointer in a similar way you convert an array to a pointer.
Another problem: Returning a 2D matrix as 'char**' is only meaningful if the matrix is implemented using an array of pointers, each pointer pointing to an array of characters. As explained previously, a 2D matrix in C is just a flat array of characters. The most you can return is a pointer to the [0][0] entry, a 'char*'. There's a mismatch in the number of indirections.

Runtime error in dynamically allocating 2D array in C

I am trying to dynamically allocate a 2D array, put some values, and print output. However it seems that I am making mistake in getting input to program in atoi() function.
Basically when we assign a static 2D array, we declare it as say int a [3][3]. So 3*3 units if int, that much memory gets allocated. Is same thing holds for allocating dynamic array as well?
Here is my code:
#include<stdio.h>
#include<stdlib.h>
int main(int arg,char* argv)
{
int rows = atoi(argv[1]);
int col = atoi(argv[2]);
int rows =3;
int col=3;
int i,j;
int (*arr)[col] = malloc(sizeof (*arr)*rows);
int *ptr = &(arr[0][0]);
int ct=1;
for (i=0;i<rows;i++)
{
for(j=0;j<col;j++)
{
arr[i][j]=ct;
ct++;
}
}
printf("printing array \n");
for (i=0;i<rows;i++)
{
for(j=0;j<col;j++)
{
printf("%d \t",arr[i][j]);
}
printf("\n");
}
free(arr);
return (0);
}
Program crashes in runtime. Can someone comment?
The first issue I see is this line:
int (*arr)[rows][col] = malloc(sizeof (*arr) * rows);
This is not problematic at all because you are in fact allocating more memory than you need. This would suffice:
int (*arr)[rows][col] = malloc(sizeof (*arr));
sizeof *arr is enough because *arr is of type int [rows][cols]; the memory you want is exactly the size of that array. The sizeof operator, when applied to arrays, gives you the count for the whole array.
The main problem with your code, however, is how you use arr. You are indexing it with arr[i][j], but instead, you should be using (*arr)[i][j], because arr is not an array, it's a pointer to an array. You need to dereference it before any further indexing - as simple as that. arr[i][j] is equivalent to *(*(arr+i)+j). Note that i should be an offset into *arr, not an offset on arr. That's why you need to dereference arr before indexing.
Since you're already using variable-length arrays, you may take advantage of that:
int (*arr)[col] = malloc(sizeof *arr * rows);
This way you can simply access elements with the usual syntax arr[i][j] without worrying about pointers and dereferences, pointer arithmetic will do all the work for you.
Also since indexes start from 0 your tests should look like i < rows and j < col.
And you have some minor errors for the wrong main declaration and the second printf.

Allocating 2-D array in C

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];

Resources