Learning C and this confusing me:
#include <stdio.h>
int main(){
int m[5][5];
int count = 0;
for(int i = 0; i < 5; i++){
for(int j = 0; j < 5; j++){
m[i][j] = count++;
}
}
int **p = m;
int (*k)[5] = m;
printf("%p\t%p\t%p", *p, *k, *m);
return 0;
}
that's what has been printed:
0x100000000 0x7ffff1fc9d70 0x7ffff1fc9d70
I'm really confused why dereference *p is 0x100000000, shouldn't it be 0x7ffff1fc9d70?
You’re thinking that m is of type int **, right?
It’s not. If you had done this, it would be:
int *m[5];
That make an array of five pointers to int, so m would be pointer to pointer to int.
However, if you do this:
int m[5][5];
You get enough space for 25 ints, which the compiler will access as a 5x5 two-dimensional array. p points to the beginning of that array. Dereference it, and the compiler reads the beginning of that array and interprets it as a pointer to int. Change the numbers you’re filling it with, and you’ll get different pseudo-pointers.
Related
code:
int arr[5] = {1,2,3,4,5};
int (*p)[5] = &arr;
printf("p:%p\n",p);
printf("*p:%p\n",*p);
result: p = *p = arr = 0x7ffee517c830 they are all the address of the array
The right way to use p to visit arr[i] is *(*p+i)
The type of pointer p is int(*)[5], so p point to an array which type is int [5]. But we can't say that p point to an invisible shell of arr, p is a variable after all. It stores the address of arr, which is also the address of arr[0], the first element of arr.
I thought *p will get me 1, which is the first element of arr.
The dereference operation means take the value in p as address and get the value from this address. Right?
So p stores the address of arr,which is 0x7ffee517c830 here, and 1 is stored in this address. Isn't **p illegal? The first dereference give us 1, and second dereference will use 1 as address which is illegal.
What I am missing?
The result of *p is an lvalue expression of array type. Using (*p) is exactly the same as using arr in any expression you could now think of.
For example:
&*p means &arr
**p means *arr (which is legal).
(*p)[i] means arr[i].
sizeof *p means sizeof arr.
Arrays are not special in this regard. You can see the same phenomenon with int x; int *q = &x;. Now *q and x have exactly the same meaning.
Regarding your last paragraph, I think you are confusing yourself by imagining pointers as glorified integers. Some people teach pointers this way but IMO it is not a good teaching technique because it causes the exact confusing you are now having.
If you dereference an int(*)[5] you get an int[5] and that's all there is to it. The data type matters in dereferencing. It does not make sense to talk about "dereferencing 0x7ffee517c830". Again this is not peculiar to arrays; if you dereference a char ***, you get a char ** etc.
The only way in which arrays are "different" in this discussion is what happens if you try to do arithmetic on them, or output them, etc. If you supply an int[5] as a printf argument for example, there is implicit conversion to int * pointing at the first of those 5 ints. This conversion also happens when applying the * operator to an int[5], which is why you get an int out of that.
p is declared as a 'pointer to int[5]'.
arr is declared as an 'int[5]`
so the initializer p = &arr; is not really that strange. If you substituted any primitive type for int[5] you wouldn't bat an eye.
*p is another handle on arr. so (*p)[0] = 1.
This really only comes up in wierd cases. It's most natural where you dereference the pointer-to-array using the subscript operator. Here's a contrived example where I want to pass a table as argument.
#include <stdio.h>
int print_row_range(int (*tab) [2], int first, int last)
{
int i;
for(i=first; i<= last; i++)
{
printf("{%d, %d}\n", tab[i][0], tab[i][1]);
}
}
int main(int argc, char *argv[])
{
int arr[3][2] = {{1,2},{3,4},{5,6}};
print_row_range(arr,1,2);
}
This example treats the table as an array of rows.
Dereferencing doesn't give you a value. It gives you an object, which can be used as a value of its type if it can be converted to.
*p, being identical to arr, is an object of an array of 5 ints, so if you want to get an integer from the array, you must dereference it again like (*p)[3].
Consider a bigger example:
int arr[5][5];
int (*p)[5] = arr;
Now you get arr[0] with *p, which itself is an array of 5. Here comes the difference:
*( p+1) == arr[1];
*(*p+1) == arr[0][1];
^ ^^^
Got the point?
One use case is to be able to allocate with malloc an 2D (or more) pointer of arrays with only one malloc:
#include <stdio.h>
#include <stdlib.h>
static int (*foo(size_t n))[42] {
return malloc(sizeof *foo(0) * n);
// return malloc(sizeof(int [n][42]); works too
}
int main(void) {
size_t n = 42;
int (*p)[42] = foo(n);
if (!p) {
return 1;
}
printf("p:");
int accu = 0;
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < sizeof *p / sizeof **p; j++) {
p[i][j] = accu++;
printf(" %d", p[i][j]);
}
}
printf("\n");
free(p);
}
I think this very funny.
One more with VLA:
#include <stdio.h>
#include <stdlib.h>
static void *foo(size_t elem, size_t n, size_t m) {
return malloc(elem * n * m);
}
int main(void) {
size_t n = 42;
int (*p)[n] = foo(sizeof **p, n, n);
if (!p) {
return 1;
}
printf("p:");
int accu = 0;
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < sizeof *p / sizeof **p; j++) {
p[i][j] = accu++;
printf(" %d", p[i][j]);
}
}
printf("\n");
free(p);
}
Here is a C program in textbook, it asks a 3*5 2D array from users and prints the third line.
I am confused with int* p[5]. Why here needs to have [5], I think just int* p is OK. It can repeatedly add and point to the next memory space in the int array. And can anyone explain how pointer works in this program?
#include <stdio.h>
int main(void){
int a[3][5];
int i,j;
int *p[5];
p = &a[0];
printf("Please input:\n");
for(i = 0; i < 3; i++){
for(j = 0; j<5;j++){
scanf("%d\n",(*(p+i))+j);
}
}
p = &a[2];
printf("the third line is:\n");
for(j = 0; j<5; j++){
printf("%5d", *((*p)+j));
}
printf("\n");
}
int *p[5];
is an array of five pointers to int.
What you want is a pointer to an array of five ints
int (*p)[5];
because &a[0] is the address of the 1st element of a which is an int[5].
The compiler should have clearly issued at least a warning on this, if not an error, which would be expected.
More on this here: C pointer to array/array of pointers disambiguation
Hi I'm new to the C language, can someone explains what ** symbol mean.
typedef struct _TREENODE {
struct _TREENODE *Left, *Right;
TCHAR key[KEY_SIZE];
LPTSTR pData;
} TREENODE, *LPTNODE, **LPPTNODE;
If x is a pointer, *x dereferences it. **x is the same as *(*x), so **x dereferences a pointer to a pointer. (eg, it is the thing that is pointed to by the thing that x opints to).
** is a pointer to pointer, it is also used for dereferencing a pointer variable.
eg: int a=10,*b,**c;
b=&a;
c=&b;
printf("the a value is:%d\n",a);
printf("the b value is:%d\n",*b);
printf("the c value is:%d\n",**c);
just execute this code you will get the idea about pointer to pointer.
In you want to change a variable, you pass it by pointer (to the variable).
And if you want to change a pointer, you also pass it by pointer (to the pointer) which is a double pointer.
There are two things to know about * in C:
It's an operation. Doing *x on a pointer dereferences that pointer. Doing **x on a pointer can dereference a pointer to a pointer, and so on.
It's a type. Declaring a type of int *x means that it's a pointer to an int type. Declaring int **x means that it's a pointer to a pointer to an int type.
Example:
int main() {
int foo = 4;
int *bar = &foo; // declaring a pointer to int type *bar
int **baz = &bar; // declaring a pointer to a pointer to int type **baz
printf("foo: %d, *bar: %d, **baz: %d\n", foo, *bar, **baz); // derefencing the pointer *bar and **baz
return 0;
}
In a declaration, ** means pointer to a pointer. When evaluating an expression, ** dereferences a pointer to a pointer.
int** p; // Declares p to be a pointer to a pointer.
And...
**p = 10; // Dereferences p and assigns 10 to a memory location.
One common use of pointers to pointers is to represent dynamic 2D arrays. For example, if you want to create a matrix of M rows and N columns, you could do:
int** matrix = malloc(M*sizeof(*matrix));
int i = 0, j = 0;
for ( i = 0; i < M; ++i )
matrix[i] = malloc(N*sizeof(*matrix[0]));
Usage of the double pointer:
for ( i = 0; i < M; ++i )
for ( j = 0; j < N; ++j )
matrix[i][j] = 0; // Assigns a value to the element
// at the i-th row and j-th column.
If you want to use string pointer dereferencing, you would use:
for ( i = 0; i < M; ++i )
for ( j = 0; j < N; ++j )
*(*(matrix+i)+j) = 0;
Memory allocated for the matrix has to be freed in two passes also.
for ( i = 0; i < M; ++i )
free(matrix[i]);
free(matrix);
** means a pointer to a pointer.
Most of the time I like to think of it as "pointer(s)" to "a memory area". Which in fact may be a little redundant.
For example, suppose you have to dynamically store several words on memory, how would you do that? There are several ways to do this, but I'll provide an example that illustrate the use of **.
Now, suppose you want to store three words: hi, hello and goodbye
hi, hello and goodbye are strings, they consume, 2, 5 and 7 bytes on memory respectively. Well, in fact it's 3, 6 and 8 bytes because of the \0, but lets not get into many details.
But one thing is clear, we need three memory areas to hold these strings and also three pointers to reference these memory areas later.
Note that one can just declare three pointers that points to these memory areas, but, would you be willing to declare one thousand pointers to hold one thousand words? This is where ** kicks in.
Example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUMBER_OF_WORDS 3
int
main(int argc, char **argv)
{
int i;
char **words;
/* pointers */
words = malloc(sizeof(char*)*NUMBER_OF_WORDS);
/* memory areas*/
words[0] = strdup("Hi");
words[1] = strdup("Hello");
words[2] = strdup("Goodbye");
for(i=0; i < NUMBER_OF_WORDS; i++)
printf("%d) %s\n", i, words[i]);
for(i=0; i < NUMBER_OF_WORDS; i++)
free(words[i]); /* memory area */
free(words); /* pointers */
return 0;
}
Here is my code that works. The function initializes the array, a, to values 0 - 3
int main(void)
{
int a[4];
pointer(a);
return 0;
}
void pointer(int* a)
{
int *p, i;
p = a;
for(i = 0; i < 4; i++)
{
*a++ = i;
printf(" %d", p[i]);
}
}
But when I combine it all into main(), it no longer works.
int main(void)
{
int a[4], *p, i;
p = a;
for(i = 0; i < 4; i++)
{
*a++ = i;
printf("%d", p[i]);
}
return 0;
}
Instead, it prints out memory addresses or something. It works when I dynamically allocate a[], so I'm guessing it has something to do with the way a[] is managed in memory. Can someone tell me why the second main() doesn't work?
In the function pointer, the argument a is a pointer. But in main, a is an array, you can't modify an array name, so *a++ = i is invalid.
I can't even compile your code, and the error illustrates why:
$ gcc -o foo foo.c
./foo.c:9:11: error: cannot increment value of type 'int [4]'
*a++ = i;
~^
1 error generated.
You aren't actually using a pointer in your code at all. If you change it as follows, it works as you expect:
#include <stdio.h>
int main(void)
{
int a[4], i;
int* p = a;
for(i = 0; i < 4; i++)
{
*p++ = i;
printf("%d", a[i]);
}
return 0;
}
C arrays decay into pointers in some circunstances, but they aren't pointers. Use p instead of a.
It works when you dynamically allocate a because malloc() returns a pointer, not an array.
you should know the differences between array and pointer.I suggest .
In function,the array you put in will turn to pointer(point to first element of array),it's a variable of pointer,so you can do increasement,in main,a is a address of first element,it's constant,so you can't change.you should change pointer p.
In functions you'r passing the array address point to a pointer. and pointer is accessing each variable when u increment it. this is called a walking pointer.
but in case when u use it in main you'r assuming that array is a simple . Think of an array declared by compiler like
int *const array;
so when you try to increment it. it pops an error. so use one more Walking pointer inside
main so u traverse the array
I don't understand why this works:
void main() {
int * b;
b = (int *)malloc(sizeof(int));
*b = 1;
printf("*b = %d\n", *b);
}
while this does not (gets segmentation fault for the malloc()):
void main() {
int ** a;
int i;
for (i = 0; i<= 3; i++) {
a[i] = (int*)malloc(sizeof(int));
*(a[i]) = i;
printf("*a[%d] = %d\n", i, *(a[i]));
}
}
since I find a[i] is just like b in the first example.
BTW, a[i] is equal to *(a+i), right?
You need to allocate memory for a first, so that you can access its members as a[i].
So if you want to allocate for 4 int * do
a = malloc(sizeof(int *) * 4);
for (i = 0; i<= 3; i++) {
...
}
or define it as array of integer pointers as
int *a[4];
a is a 2 dimensional pointer, you have to allocate both dimension.
b is a 1 dimensional pointer, you have to allocate only one dimension and that's what you're doing with
b = (int *)malloc(sizeof(int));
So in order the second example to work you have to allocate the space for the pointer of pointer
void main() {
int ** a;
int i;
a = (int**)malloc(4*sizeof(int*));
for (i = 0; i<= 3; i++) {
a[i] = (int*)malloc(sizeof(int));
*(a[i]) = i;
printf("*a[%d] = %d\n", i, *(a[i]));
}
The allocated pointer is written to uninitialized memory (you never set a to anything), causing undefined behavior.
So no, it's not at all equivalent to the code in the first example.
You would need something like:
int **a;
a = malloc(3 * sizeof *a);
first, to make sure a holds something valid, then you can use indexing and assign to a[0].
Further, this:
a[i] = (int*)malloc(sizeof(int));
doesn't make any sense. It's assigning to a[i], an object of type int *, but allocating space for sizeof (int).
Finally, don't cast the return value of malloc() in C.
actually malloc it's not that trivial if you really want safe and portable, on linux for example malloc could return a positive response for a given request even if the actual memory it's not even really reserved for your program or the memory it's not writable.
For what I know both of your examples can potentially return a seg-fault or simply crash.
#ruppells-vulture I would argue that malloc is really portable and "safe" for this reasons.