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?
Related
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!
So at the end of each iteration that I'm doing, I want to make my array be equal to my new array (which I have called array_new). I want every element of array to take the same value as is in array_new but I'm interested in getting my code as quick as possible and so copying everything across element-by-element as this current code does isn't an option:
for(i=0;i<N_a;i++) {
for(j=0;j<N_b;j++) {
array[i][j] = array_new[i][j];
}
}
This takes quite a long time because my values of N_a and N_b are very large. Is there a way to simply change what each of them point to so that I can start my next iteration more quickly? I've tried doing stuff like
double *temp = *array;
*array = *array_new;
*array_new = temp;
in order to try and avoid a slow element-by-element copying procedure but it doesn't seem to work for me. Effectively what I'm trying to make happen is for every element of array point to the corresponding element in array_new but I can't work out how to make the pointers do that.
Any help would be much appreciated!
Since the memory size of your array is fixed, you can simply copy the memory block from one pointer to the other. It doesn't get any faster than that.
In c/c++ you could use memcpy if that is the language you are using. Every language has something equivalent.
Edit: since you confirmed use of c I can get more detailed:
memcpy(array_new,array,sizeof(VARIABLE_TYPE_of_ARRAY_ELEMENT)*N_a*N_b);
Your pointer-swap code is just a little bit off: you are dereferencing your pointers where you shouldn't. After all, the point of that code is to avoid copying data by just swapping two pointers. Here are the correct versions (depending on whether you use a true 2D array or an array of pointers to arrays):
//array is declared as
double (*array)[N_b];
double (*temp)[N_b] = array;
array = array_new;
array_new = temp;
or
//array is declared as
double** array;
double** temp = array;
array = array_new;
array_new = temp;
This is all you need, and it's definitely the fastest possible way to exchange contents of two buffers. Much faster than memcpy()...
If you just want to swap the pointers, not physically copying the data, and to still be able to access the arrays using indexes, here is an example of how it can be done:
#define N_a 2
#define N_b 3
typedef struct arr
{
int val[N_a][N_b];
} arr;
arr array = {{{11,12,13},{14,15,16}}};
arr array_new = {{{21,22,23},{24,25,26}}};
int main()
{
arr *p_array;
arr *p_array_new;
p_array = &array;
p_array_new = &array_new;
printf("%d %d\n", p_array->val[1][2], p_array_new->val[1][2]);
// output: 16 26
p_array = &array_new;
p_array_new = &array;
printf("%d %d\n", p_array->val[1][2], p_array_new->val[1][2]);
// output: 26 16
}
Two answer this, you first need to understand how the array is represented in memory. E.g. see this question: How are multi-dimensional arrays formatted in memory?
So first we need to know if you have a static array or not. If it is a static array then the task is particularly simple, because the data is laid out contiguously in memory. This means that if you have a 2x2 static array, with the content {{9, 8}, {7, 6}} your memory could look like this:
Address 0 1 2 3 4 5 6 7 8
Content ? ? 9 8 7 6 ? ? ?
In this case your variable which is declared like this:
int[2][2] myArray;
is actually a pointer to address "2" and you can easily copy the whole thing. with memcpy:
int [2][2] newArray;
memcpy(&newArray, &myArray, sizeof(int)*2*2);
Notice that this copies starting from wherever "myArray" points (in my example that is 2) as many bytes as 2*2*sizeof(int). So 4 times the size of int. (For simplicity my example assume a size of one byte for an int, but of course on most systems it is 4 byte).
If you have a dynamic array, then it is a different story. In this case your memory for your array declared like this:
int** myArray;
may well look like this:
Address 0 1 2 3 4 5 6 7 8
Content 9 8 0 6 ? ? 7 6 ?
Note that the pointer myArray still points to the Address "2". However at the address "2" you don't find the first value, but instead another pointer which points to "0". And here you find the values of the first "row" which are 9 and 8.
Next to the address "2" in number "3" you find the pointer to your second "row" which starts at position 6. As you can see, you can still find all your data, but you cannot copy them in a single go. To copy the whole array you will at least need the outer row:
int SIZE_X = 2;
int SIZE_Y = 2;
int** newArray = malloc(sizeof(int*)*SIZE_X);
for(i = 0; i < SIZE_X; ++i) {
newArray[i] = malloc(sizeof(int)*SIZE_Y);
memcpy(newArray[i], myArray, SIZE_Y*sizeof(int));
}
This should be faster then using two loops, as memcpy can use more efficient ways to copy than a copy loop.
I want to get numbers from the keyboard (or from a file: ./a.out < file) and store them in an array. The idea is that the length of the array is unknown.
#include <stdio.h>
#include <stdlib.h>
int* newElem(){
int* elm= malloc(sizeof(int));
if (elm == NULL) {
printf("\nError: memory allocation failed.\n");
exit(-1);
}
return elm;
}
int main(){
int *array,x,size,i=0;
while( scanf("%d",&x)==1 ){
array= newElem();
array[i]=x;
i++;
}
size=i;
free(array);
printf("size=%d",size);
return(0);
}
Why does this crash after I enter:
1 2 3 4 5 6 7 8
In your code
array= newElem();
is going to overwrite the existing pointer (memory) every time. so, array[i] becomes invalid, which essentially is an access out of bounds which in turn invokes undefined behavior. You need to use realloc() to re-size the allocated memory.
Simple.
array= newElem();
array[i]=x;
i++;
newElem() always return int[1] and you tried to access [n]
First you need to know that an array is a sequence of consecutive addresses.
This means that if the address of the first element is 0, the address of the second element will be 1, and the next 2, so on...
When you say x[10] in C, you are in fact saying *(x + 10), which means "from the first element (0), advance 10 addresses (+ 10), and give me the contents (* operator) of that address as an int.
So you see, there is a mathematical relation between elements, they are all next to each other in memory.
Now, to your code...
When you call array= newElem();, your pointer array points to the newly allocated address. However, any previous address array was pointing to before is lost, which is causing both your unexpected behavior and memory leak.
When you first call array= newElem(), lets suppose an integer is allocated at the address A, and the next time a new integer is allocated at the address B, and so on...
On first iteration, with i = 0:
while( scanf("%d",&x)==1 ){
array= newElem();
// array points to A
array[i]=x;
// array[0] = x
// or *(array + 0) = x
// same as *(array) = x
i++;
// i = 1
}
Now you will MOST LIKELY have an error (i = 1):
while( scanf("%d",&x)==1 ){
array= newElem();
// address A is lost, and now array points to B
array[i]=x;
// array[1] = x; -> likely an ERROR
// *(array + 1) = x
i++;
// i = 2
}
On the second iteration, you try to access the address NEXT TO the new address array points to, which would be C, that is why you get a violation.
Your code does not maintain a relationship between the elements of the array, you are essentially creating single integers in every iteration, and then trying
to access then but you are actually accessing invalid memory addresses.
It is not a very simple concept at first, comment if you need further clarification.
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).
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.