I have an example involving a pointer to a 2D array. Can someone help me understand what is going on in this example?
int main()
{
int i = 0, j=0, sum0=0, sum1=0;
int data[4][3] = { {23,55,50},{45,38,55},{70,43,45},{34,46,60}};
int *Ptr;
Ptr = *data; //Why is the indirection operator used here?
// Does Ptr = 23 by this assignment?
for (i=0; i<4; i++) {
sum1 = 0;
for (j = 0; j < 3; j++) {
sum1 += data[i][j];
}
if (sum1 > sum0) {
sum0 = sum1;
Ptr = *(data + i); // Seems like this statement makes Ptr
} // point one row below ... what syntax
} // can you use to access columns then?
// Is it possible to use pointer arithmetic
for (i=0; i<3; i++) // to access elements of data[i][j] that
printf("%d\n", Ptr[i]); // are not at j = 0?
return 0;
}
data is a 2 dimentional array, which has 4 rows and each row has 3 elements (ie 4 X 3).
Now, Ptr = *data; means you are storing the starting address of 1st row to the pointer variable Ptr. This statement is equivalent to Ptr = *(data + 0). Ptr = *(data + 1) - this means we are assigning 2nd row's starting address.
Then *Ptr or *(Ptr + 0) will give you the value of the first element of the row to which is pointing. Similarly, *(Ptr + 1) will give you the value of the second element of the row.
The for loop in your program is used to identify which row has the maximum value of the sum of its elements (3 elements). Once the control comes out of that for loop, Ptr will be pointing to the row which has the maximum sum of its elements and sum0 will have the value of the sum.
Consider an array int a[5];, I hope you know that a[0] and 0[a] is the same. This is because a[0] means *(a+0) and 0[a] means *(0 + a). This same logic can be used in 2 dimensional array.
data[i][j] is similar to *(*(data + i) + j). We can write it as i[data][j] also.
For more details please refer to the book "Understanding Pointers in C" by Yashavant Kanetkar.
Ptr = *data; is short for *(data+0)+0 which is a pointer for first column element of the first row. the first 0 added with data is the row no., which is indirected and takes us to the first row. * (data+0) is still a address and not a value it points to (for 2D array). So, Ptr now points to the address of first column in first row. The second zero is the column no.. So, first row and first column's memory address is chosen. Using indirection (*) again would only now give value that the address holds. like * (*(data+0)+0) or **data.
Generally, if p is pointer name,i row number and j column number,
(*(p+i)+j) would give a memory address of a element in 2D array. i is row no. and j is col no.,
*(*(p+i)+j) would give the value of that element.
*(p+i) would access the ith row
to access columns, add column number to *(p+i). You may have to declare the pointer as (*p)[columns] instead of just *p. Doing so, you are declaring pointer to an 2D array.
Using pointer arithmetic is treating 2d array like 1D array. Initialize pointer *Ptr to first element (int *Ptr = *data) and then add an no. (Ptr + n) to access the columns. Adding a number higher than column number would simply continue counting the elements from first column of next row, if that exists.
data is an array of 3-element arrays of integers. In contexts that expect a "pointer to foo", you can use an "array of foo" and it will behave like a pointer to its first element, so *data is a pointer to the first element of data, namely (so to speak) {23,55,50}.
So, the answer to the first question in the comments: No, it isn't true that Ptr = 23. (It couldn't be; Ptr is an int * and 23 is an int.)
You are correct that Ptr = *(data+i) makes Ptr point to the ith row of data. More precisely, data is an array of 3-element arrays of int, which behaves like a pointer to 3-element arrays of int; adding i to it moves past i such arrays.
The usual way to access other columns of the array is ordinary array indexing. If you refer to data[i][j], you're getting column j of row i. If you want to do it with explicit pointer arithmetic, then note that (e.g.) Ptr in the example code is of type "pointer to integer", so Ptr+1 (for instance) is element 1 of whatever row Ptr is pointing to. (But, as a matter of style, you should generally not do explicit pointer arithmetic when you don't actually need to.)
In your example the loop goes through all matrix rows to find the one whose sum of all elements holds the maximum value.
At the beginning a pointer to the first row is assigned:
Ptr = *data;
Which means that the following is true:
(Ptr[0] == 23 && Ptr[1] == 55 && Ptr[2] == 50)
Notice that Ptr is a pointer so it holds a memory address, hence Ptr is different than 23 (unless the memory address happens to be 23, which is unlikely to happen).
C allows multidimensional arrays, lays them out in memory as contiguous locations, and does more behind the scenes address arithmetic.
Consider a 2-dimensional array.
int arr[ 3 ][ 3 ] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
The compiler treats a 2 dimensional array as an array of arrays.
where an array name is a pointer to the first element within the array.
So, arr points to the first 3-element array, which is actually the first row (i.e., row 0) of the two-dimensional array.
Similarly, (arr + 1) points to the second 3-element array (i.e., row 1) and so on.
The value of this pointer, (arr + 1), refers to the entire row.
Since row 1 is a one-dimensional array, (arr + 1) is actually a pointer to the first element in row 1.
Now add 2 to this pointer. Hence, ((arr + 1) + 2) is a pointer to element 2 (i.e., the third element) in row 1. The value of this pointer, ((arr + 1) + 2), refers to the element in column 2 of row 1.
Related
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.
I'm trying to understand this code:
struct mys {
double d[128];
};
void my_func(int iters) {
int i;
struct mys *ptr = malloc(iters *sizeof(struct mys));
for(i = 0; i < iters; i++) {
ptr[i].d[0] = (double)i;
}
free(ptr);
}
What I know:
mys is of size 8 * 128 (size of double is 8, it's an array of 128 doubles)
*ptr is of size iters * (8 * 128)
What is going on here:
ptr[i].d[0] = (double)i;
?
What I know:
// ptr->d is the address of the first part of d
// same as (*ptr).d
// BECAUSE d IS A STRUCT
// ptr->d[i] is the actual value. so, 0.0000
// same as (*ptr).d[i]
Thanks in advance.
ptr[i] is the value at index i, so starts at 0.0000.
d is not initialized, it is just the name of the member of a struct. How can we just d here?
What I think:
*ptr is multiple (iters) structs.
So, ptr[0] is the first struct, ptr[1] is the second struct, etc.
ptr[i].d access the ith struct's d array.
ptr[i].d[0] accesses the first index of the d array. So the line above sets that number to double(i).
So this really only sets the first element of each struct to be 0. Am I right?
But when iters is 2, and I try:
for(int i = 0; i < iters; i++) {
printf("%p\n", ptr[200].d);
}
it still prints an address. Why is that?
What is going on here: ptr[i].d[0] = (double)i;?
This:
struct mys *ptr = malloc(iters *sizeof(struct mys));
allocates memory for an array of structs, called ptr.
This line of code:
ptr[i].d[0] = (double)i;
assigns i to the first cell of the array d, of the i-th struct, in the array ptr.
i is casted to double, because d is an array of doubles, and i is declared as int.
when iters is 2, and I try: for(int i = 0; i < iters; i++) { printf("%p\n", ptr[200].d); } it still prints an address. Why is that? Shouldn't it be out of range since ptr is only 2 structs?
This is definitely out of range, since arrays are 0-indexed.
However, that attempt invokes Undefined Behavior (UB), which means that you don't know how the code is going to behave. For example, in your computer it prints an address, in my computer it might cause a segmentation fault, and so on...
So this really only sets the first element of each struct to be 0. Am I right?
It copies the index i, converted to type double, into the first element of each struct. Otherwise you are right.
Regarding the expression ptr[200].d, this is the same as &(ptr[200]) because the array d[] is the sole element of a mys object. Because a double is eight bytes wide, each mys object occupies (8 bytes)(128) = 1 kiB. Therefore, &(ptr[200]) == ptr + 200*1024. The last is an address 200 kiB past the beginning of *ptr. Whether the address has meaning depends on whether anything meaningful is stored there.
I have currently trouble understanding the following scenario:
I have a multidimensional array of Strings and I want to address it by using pointers only but I always get a Segmentation Fault when using the array annotation on the pointer. This is just an example code I want to use the 3D array in a pthread so I want to pass it in via a structure as a pointer but it just doesn't work and I would like to know why? I thought pointers and arrays are functionally equivalent? Here is the sample code:
#include <stdio.h>
void func(unsigned char ***ptr);
int main() {
// Image of dimension 10 times 10
unsigned char image[10][10][3];
unsigned char ***ptr = image;
memcpy(image[0][0], "\120\200\12", 3);
// This works as expected
printf("Test: %s", image[0][0]);
func(image);
return 0;
}
void func(unsigned char ***ptr) {
// But here I get a Segmentation Fault but why??
printf("Ptr: %s", ptr[0][0]);
}
Thanks in advance for your help :)
I think maybe strdup confuses the issue. Pointers and arrays are not always equivalent. Let me try to demonstrate. I always avoid actual multi-dimension arrays, so I may make a mistake here, but:
int main()
{
char d3Array[10][10][4]; //creates a 400-byte contiguous memory area
char ***d3Pointer; //a pointer to a pointer to a pointer to a char.
int i,j;
d3Pointer = malloc(sizeof(char**) * 10);
for (i = 0; i < 10; ++i)
{
d3Pointer[i] = malloc(sizeof(char*) * 10);
for (j = 0; j < 4; ++j)
{
d3Pointer[i][j] = malloc(sizeof(char) * 4);
}
}
//this
d3Pointer[2][3][1] = 'a';
//is equivalent to this
char **d2Pointer = d3Pointer[2];
char *d1Pointer = d2Pointer[3];
d1Pointer[1] = 'a';
d3Array[2][3][1] = 'a';
//is equivalent to
((char *)d3Array)[(2 * 10 * 4) + (3 * 4) + (1)] = 'a';
}
Generally, I use the layered approach. If I want contiguous memory, I handle the math myself..like so:
char *psuedo3dArray = malloc(sizeof(char) * 10 * 10 * 4);
psuedo3dArray[(2 * 10 * 4) + (3 * 4) + (1)] = 'a';
Better yet, I use a collection library like uthash.
Note that properly encapsulating your data makes the actual code incredibly easy to read:
typedef unsigned char byte_t;
typedef struct
{
byte_t r;
byte_t g;
byte_t b;
}pixel_t;
typedef struct
{
int width;
int height;
pixel_t * pixelArray;
}screen_t;
pixel_t *getxyPixel(screen_t *pScreen, int x, int y)
{
return pScreen->pixelArray + (y*pScreen->width) + x;
}
int main()
{
screen_t myScreen;
myScreen.width = 1024;
myScreen.height = 768;
myScreen.pixelArray = (pixel_t*)malloc(sizeof(pixel_t) * myScreen.height * myScreen.width);
getxyPixel(&myScreen, 150, 120)->r = 255;
}
In C, you should allocate space for your 2D array one row at a time. Your definition of test declares a 10 by 10 array of char pointers, so you don't need to call malloc for it. But to store a string you need to allocate space for the string. Your call to strcpy would crash. Use strdup instead. One way to write your code is as follows.
char ***test = NULL;
char *ptr = NULL;
test = malloc(10 * sizeof(char **));
for (int i = 0; i < 10; i++) {
test[i] = malloc(10 * sizeof(char *));
}
test[0][0] = strdup("abc");
ptr = test[0][0];
printf("%s\n", ptr);
test[4][5] = strdup("efg");
ptr = test[4][5];
printf("%s\n", ptr);
Alternatively, if you want to keep your 10 by 10 definition, you could code it like this:
char *test[10][10];
char *ptr = NULL;
test[0][0] = strdup("abc");
ptr = test[0][0];
printf("%s\n", ptr);
test[4][5] = strdup("efg");
ptr = test[4][5];
printf("%s\n", ptr);
Your problem is, that a char[10][10][3] is something very different from a char***: The first is an array of arrays of arrays, the later is a pointer to a pointer to a pointer. The confusions arises because both can be dereferenced with the same syntax. So, here is a bit of an explanation:
The syntax a[b] is nothing but a shorthand for *(a + b): First you perform pointer arithmetic, then you dereference the resulting pointer.
But, how come you can use a[b] when a is an array instead of a pointer? Well, because...
Arrays decay into pointers to their first element: If you have an array declared like int array[10], saying array + 3 results in array decaying to a pointer of type int*.
But, how does that help to evaluate a[b]? Well, because...
Pointer arithmetic takes the size of the target into account: The expression array + 3 triggers a calculation along the lines of (size_t)array + 3*sizeof(*array). In our case, the pointer that results from the array-pointer-decay points to an int, which has a size, say 4 bytes. So, the pointer is incremented by 3*4 bytes. The result is a pointer that points to the fourths int in the array, the first three elements are skipped by the pointer arithmetic.
Note, that this works for arrays of any element type. Arrays can contain bytes, or integers, or floats, or structs, or other arrays. The pointer arithmetic is the same.
But, how does that help us with multidimensional arrays? Well, because...
Multidimensional arrays are just 1D arrays that happen to contain arrays as elements: When you declare an array with char image[256][512]; you are declaring a 1D array of 256 elements. These 256 elements are all arrays of 512 characters, each. Since the sizeof(char) == 1, the size of an element of the outer array is 512*sizeof(char) = 512, and, since we have 256 such arrays, the total size of image is 256*512. Now, I can declare a 3D array with char animation[24][256][512];...
So, going back to your example that uses
char image[10][10][3]
what happens when you say image[1][2][1] is this: The expression is equivalent to this one:
*(*(*(image + 1) + 2) + 3)
image being of type char[10][10][3] decays into a pointer to its first element, which is of type char(*)[10][3] The size of that element is 10*3*1 = 30 bytes.
image + 1: Pointer arithmetic is performed to add 1 to the resulting pointer, which increments it by 30 bytes.
*(image + 1): The pointer is dereferenced, we are now talking directly about the element, which is of type char[10][3].
This array again decays into a pointer to its first element, which is of type char(*)[3]. The size of the element is 3*1 = 3. This pointer points at the same byte in memory as the pointer that resulted from step 2. The only difference is, that it has a different type!
*(image + 1) + 2: Pointer arithmetic is performed to add 2 to the resulting pointer, which increments it by 2*3 = 6 bytes. Together with the increment in step 2, we now have an offset of 36 bytes, total.
*(*(image + 1) + 2): The pointer is dereferenced, we are now talking directly about the element, which is of type char[3].
This array again decays into a pointer to its first element, which is of type char*. The size of the element is now just a single byte. Again, this pointer has the same value as the pointer resulting from step 5, but a different type.
*(*(image + 1) + 2) + 1: Pointer arithmetic again, adding 1*1 = 1 bytes to the total offset, which increases to 37 bytes.
*(*(*(image + 1) + 2) + 1): The pointer is dereferenced the last time, we are now talking about the char at an offset of 37 bytes into the image.
So, what's the difference to a char***? When you dereference a char***, you do not get any array-pointer-decay. When you try to evaluate the expression pointers[1][2][1] with a variable declared as
char*** pointers;
the expression is again equivalent to:
*(*(*(pointers + 1) + 2) + 3)
pointers is a pointer, so no decay happens. Its type is char***, and it points to a value of type char**, which likely has a size of 8 bytes (assuming a 64 bit system).
pointers + 1: Pointer arithmetic is performed to add 1 to the resulting pointer, which increments it by 1*8 = 8 bytes.
*(pointers + 1): The pointer is dereferenced, we are now talking about the pointer value that is found in memory at an offset of 8 bytes of where pointers points.
Further steps depending on what actually happened to be stored at pointers[1]. These steps do not involve any array-pointer-decay, and thus load pointers from memory instead.
You see, the difference between a char[10][10][3] and a char*** is profound. In the first case, the array-pointer-decay transforms the process into a pure offset computation into a multidimensional array. In the later case, we repeatedly load pointers from memory when accessing elements, all we ever have are 1D arrays of pointers. And it's all down to the types of pointers!
I am studying the basics in C and I am confused about the strings and arrays.
#include<stdio.h>
int main()
{
char arr[2][4] = {1,2,3,4,5,6,7,8};
printf("%u %u\n",arr,arr+1);
printf("%d",*(*(arr+1)+2) );
return 0;
}
Here arr and arr+1 are adjacent locations, but in the second printf arr+1 goes straight to the zero index element of the second array. How is this legal? I have thought that to go to the second array it should be &arr+1.
What i learned is --> for one dimensional array:
arr[7]={1,2,3,4,5,6,7};
here arr and &arr should not be considered same(although they print same value, but the sense of this information is completely different) . Thats why arr+1 and &arr+1 will not be same too. &arr gives the address of a data type that is a container of 7 integers thats why &arr+1 goes to the subsequent array type that is also a container of 7 integers .
so
arr = 5796 , &arr = 5796 (both are base address but arr is the address of
1st element while &arr is the address of the whole array)
arr+1 = 5800 ,&arr+1 = (5796+(7X4))=5797+28 = 5825(this is address of some
new array)
for two dimensional array the concept is same:
arr[2][4]={1,2,3,4,5,6,7,8};
now arr is here is also a pointer that points to array individual elements so arr and arr+1 are the addresses of its successive elements (and those elements are {1,2,3,4} and {5,6,7,8})_
and in the same way &arr and &arr+1 gives the base addresses of two arrays that have 2x4=8 elements so to &arr and &arr+1 are addresses of two similar sized arrays one after another.
So
arr = 5796 , arr+1 = 5796+(4*3)=5796+12 = 5808
&arr = 5796 , &arr+1 = 5796+(4*7)=5796+ 28= 5824
Now we can see in 2 dimensional array to reach an individual element there are two addresses associated.
1)arr (that gives which element to choose between the two inside arrays)
2)*arr (that gives which element in that particular element(array)
so we need to dereference two times if we want to reach to the data.
arr=5796(first array), *arr=5796(first element address), **arr = 1 (1st element)
arr+1=5812(second array), *(arr+1) = 5812(first element address), *(*(arr+1))=5(first element)
arr=5796,*arr=5796, *arr+1=5796+1(second element), *(*arr+1)=2 (second element)
now the syntax for arrays:
*arr = arr[0]
**arr = arr[0][0]
*arr+1 = arr[0]+1
**arr+1 = arr[0][0]+1
*(*arr+1) = *(arr[0]+1) = arr[0][1]
*(*(arr+1)+1) = *(arr[1]+1) = arr[1][1]
there are some other ways to write arrays
3[arr[1]] = arr[1][3]
-3[arr[1]] = -arr[1][3]
*(1[arr]+2) = *(arr[1]+2) = arr[1][2]
the concept can be expanded to 3 dimensional array too , but this is the minimum every beginner should understand.Correct me if I am wrong anywhere conceptually or syntactically.
Because arr is a two dimensional array.
*(*(arr+1)+2)) is equivalent to arr[1][2].
printf("%d",*(*(arr+1)+2) );
break this it into two statements
*(arr+1) means arr[1]
like this
*(arr[1] + 2) means arr[1][2]
Declaration
char arr[2][4] = {1,2,3,4,5,6,7,8};
means
char arr[2][4] = {
{1,2,3,4}, // row 0
{5,6,7,8} // row 1
};
Passing the array name arr to printf means it decays to pointer to the first element (row 0) of the array arr[2] and is of type int (*)[4] (thought 2D array as 1D array of 2 elements which are array of 4 elements each).
I have thought that to go to the second array it should be &arr+1.
arr + 1 points to the second element (row 1) of the array arr[2] (and not the second element of row 1 of array arr[2][4]). By doing arr + 1, you are not adding just 1 to the pointer arr (after decay) but you are adding total number of bytes needed to store the elements in a row.
Let's understand this by a simple example: Consider arr refernce to the address 100 and size of int is 4. Then arr + 1 means your doing 100 + (4-1)*4 = 112.
Hence dereferencing (arr + 1) will give entire row 1 while dereferencing (*(arr+1)+2) will give the 3rd element of row 1, i.e, 7.
And also, %u is used for unsigned integer. To print address (pointer value) use %p specifier in your first printf statement.
arr+1 and &arr+1 in this context are exactly the same thing, because arr is an array which implicitly degrades to a pointer, or have its address taken explicitly, which amounts to the same thing.
Adding 1 to the array goes to its second element, as you know. And arr is an array of arrays, so its second element is the second sub-array.
If you want the second element of the first sub-array, try arr[0]+1, which is equivalent to &arr[0][1].
array you using is character so each field take 1 byte. arr and arr+1 will not be in adjacent location.
I think when you checking output of arr and arr+1 difference is 4 so you keep the integer in mind and telling it was in adjacent location.
&arr[0] = address of 1st element of 1st row
&arr[1] = address of 1st element of 2nd row
change your datatype from char to int you will understand more.
Check the output of below program.
#include<stdio.h>
int main()
{
char arr[2][4] = { 1,2,3,4,
5,6,7,8 };
printf("%u\n", &arr[0][0]);
printf("%u\n", &arr[0][4]);
printf("%u\n", &arr[1][0]);
printf("%u\n", &arr[1][4]);
printf("%d\n",*(*(arr+1)+2) ); // equal to arr[1][2]
printf("%d\n", *(arr[1] + 2) );
printf("%d\n", arr[1][2]);
return 0;
}
output :
3214594184
3214594188
3214594188
3214594192
7
7
7
above program will give some warning, replace %u with %p.
When accessing char arr[ROW_COUNT][COLUMN_COUNT], arr[row][col] is equivalent to address_of_arr[col + (row * ROW_COUNT)]. Once you've wrapped your head around that it will all make a lot more sense.
arr and arr+1 should not be adjacent, there should be a difference of 4 bytes. Exactly what result are you seeing?
I am trying to increase the size of my 2D array and hm is a struct that contains the x length of the array. I am using value -99999991 to indicate the end of the array.
Is this the correct way to do it?
hm->value = realloc(hm->value,(hm->x+1)*sizeof(int));
hm->value[hm->x] = malloc(sizeof(int));
hm->value[hm->x][0] = -999999991;
hm->value[hm->x-1] = realloc(hm->value[hm->x-1],2*sizeof(int));
hm->value[hm->x-1][1] = -999999991;
hm->value[hm->x-1][0] = value;
You don't have a 2D array if it can be resized, you have a pointer to a pointer to an int.
An array:
int A[n][m];
Accessing the array: A[2][3] = 4; // Equivalent to *(A + 2*m + 3)
A variable sized 2D "array":
int **A;
A = malloc(n*m*sizeof(int));
A[2][3] = 4; // Equivalent to *A + 2*??? + 3)
The compiler doesn't know if your array is one dimensional, or if it is two dimensional then what the size of the two dimensions are. It can't calculate this any more.
Also, realloc can't put the data in the right place. Consider a 2x2 2D array going to a 2x3 2D array:
int **A = {{0,1}, {2,3}}; // for berevity - this isn't valid C!
// stored in memory as [0,1,2,3]
A = realloc(A, 2*3* sizeof(int));
New array stored in memory is [0,1, , 2, 3, ]; This required copying the data.
There are two decent solutions (though they aren't pretty):
1) Treat your 2D array as a list of 1D arrays
int **A;
A = malloc(m*sizeof(void *));
for (i = 0; i < m; ++i) {
A[i] = malloc (n*sizeof(int);
}
(now realloc should work on both of these arrays, but accessing elements will require two pointer dereferences rather than pointer arithmetic)
2) if one of the dimensions of the array is fixed then we can use a 2D array in memory and realloc it as required.
#define M 16
int **A;
A = malloc(M*n*sizeof(int)); // realloc also works
// access an element:
*(A + 3*M + 2) = 4; // (3*M is compile time constant)
In this second example we always grow at the end of our 2D array (so my example of going from 2x2 to 2x3 is illegal - the second 2 is a fixed length).