typedef struct PeoInfo
{
char name[20];
int age;
char sex[5];
char tele[12];
char addr[30];
}
struct PeoInfo c[10] = {0};
printf("p=%x\n", *c);
printf("p=%x\n", c[0]);
In this situation, sizeof(c) and sizeof(*c) have different results.
In my point of view, c is the entry of the array. But what is the *c? The result of sizeof(*c) is the size of PeoInfo. When using printf to print the address of *c and c[0], the result is also different.
I am really confused about it.
In this expression *c the array designator c is implicitly converted to a pointer to its first element of the type struct PeoInfo * and applying the dereference operator yields an object of the type struct PeoInfo.
So the expression sizeof( *c ) where the expression *c is not evaluated and only its type is determinated yields the size of an object of the type struct PeoInfo.
As the subscript operator c[0] is calculated like *( c + 0 ) that is the same as *c then these printf statements will output the same value
printf( "&*c = %p\n", ( void * )&*c );
printf( "&c[0] = %p\n", ( void * )&c[0] );
Related
What is the difference between these two declarations ? How are such variables used in C programs ? Thank you.
char *names[20];
[] takes precedence over *, so the interpretation is: names is an array of size 20. Each array element is of type pointer to char.
char (*place)[10];
In case of using parentheses to override the precedence, the * is applied first: place is a pointer to an array of size 10. Each array element is of type char.
Clockwise/Spiral Rule
char *names[20];
Applying the rule, we learn that names is a 20-element array of pointers to char values.
More clearly, names is an array of 20 char * pointers. This allocates enough memory for 20 such pointers.
sizeof(names) == sizeof(char*) * 20
char (*place)[10];
Applying the rule, we learn that place is a pointer to a 10-element array of char values.
More clearly, place is a pointer, and it points to an array of 10 char. This allocates enough memory for one such pointer.
This declaration
char *names[20];
declares an array with the name names of 20 elements of the type char *. It would be better to write it like
char * names[20];
This declaration
char (*place)[10];
declares a pointer with the name place that points to an array of 10 elements of the type char.
Here is a demonstrative program that I hope makes it more clear.
#include <stdio.h>
int main(void)
{
char * names[20] =
{
"Peter", "Bob", "Mary"
};
for ( char **p = names; *p != NULL; ++p )
{
printf( "%s ", *p );
}
putchar( '\n' );
char city[10] = "Madrid";
char (*place)[10] = &city;
puts( *place );
return 0;
}
The program output is
Peter Bob Mary
Madrid
In this declaration in the above program
char * names[20] =
{
"Peter", "Bob", "Mary"
};
three elements of the array are initialized explicitly by addresses of first characters of the string literals used as initializers. All other 17 elements of the array are implicitly initialized as null pointers.
The same program can be rewritten using typedef(s).
#include <stdio.h>
typedef char * T1;
typedef char T2[10];
int main(void)
{
T1 names[20] =
{
"Peter", "Bob", "Mary"
};
for ( char **p = names; *p != NULL; ++p )
{
printf( "%s ", *p );
}
putchar( '\n' );
T2 city = "Madrid";
T2 *place = &city;
puts( *place );
return 0;
}
The program output will be the same as shown for the previous program.
Please forgive me if the title is not 100% correct. I have a function which takes two inputs - a pointer to a string, and a pointer to a pointer to an array (?). The function I am writing is
int string_parser(char *inp, char **array_of_words[])
What I want to be doing is taking these two arguments and the function should return
the amount of words in the string array (string array is char *inp)
a pointer to an array of pointers char **array_of_words[] - each element in the array pointing to the address of the first character in each word (I apologise if that is wordy)
I have created the pointer to an array of pointers, and allocated space to this array
char **startOfWords_ptr = (char **) malloc(amountOfWords * sizeof(char*));
and have been manipulating the contents just fine. I now want to pass the array at *start_of_words back to array_of_words - but I don't understand how to do it
With *array_of_words = *(startOfWords_ptr); am I saying: a pointer to point at the starting address of the array of pointers?
Surely I am not because I don't get the same values when printing...
printf("%p\n", (void *) *array_of_words); // 0x401f2c, o
printf("%p\n", (void *) *startOfWords_ptr); // 0x401f2c, o
printf("%p\n", (void *) array_of_words[1]); // 0x401f2c, o
printf("%p\n", (void *) startOfWords_ptr[1]); // 0x401f30, t
Suggestions with comments as output
*array_of_words = (startOfWords_ptr); // This currently does not work
printf("%p, %c\n", (void *) array_of_words[0], *array_of_words[0]); // 0xcbbdd0, ;
printf("%p, %c\n", (void *) startOfWords_ptr[0], *startOfWords_ptr[0]); // 0x401f3b, o
printf("%p, %c\n", (void *) array_of_words[1], *array_of_words[1]); // 0x401f2c, o
printf("%p, %c\n", (void *) startOfWords_ptr[1], *startOfWords_ptr[1]); // 0x401f3f, t
Okay, so let's look at this from the perspective of the caller of this function:
int main( void )
{
char my_input[] = "This is a test";
char **my_output = NULL;
int count = string_parser( my_input, &my_output );
for ( int i = 0; i < count; i++ )
printf( "pointer #%d: %p\n", i, (void *) my_output[i] );
}
We know that after calling string_parser, my_output will point to the first of a sequence of pointers to char. Since we need to modify the value of my_output, we must pass a pointer to it in the call (&my_output).
This means that the prototype for string_parser needs to be
int string_parser( const char *inp, char ***array_of_words )
{
...
}
In the context of a function parameter declaration, T a[N] and T a[] are both treated as T *a, so char ***array_of_words is the same as char **array_of_words[] - both are ultimately char ***.
So given
I have created the pointer to an array of pointers, and allocated space to this array
char **startOfWords_ptr = (char **) malloc(amountOfWords * sizeof(char*));
and have been manipulating the contents just fine. I now want to pass the array at *start_of_words back to array_of_words - but I don't understand how to do it
you have it backwards - you'd assign the startOfWords_ptr to *array_of_words:
*array_of_words = startOfWords_ptr; // char ** = char **
array_of_words has one more level of indirection than startOfWords_ptr, so we need to dereference it to get the types to match. After this assignment,
*array_of_words[i] == startOfWords_ptr[i] // char * == char *
this parameter in the function signature:
char **array_of_words[]
can be re-written as:
char ***array_of_words
I.E. either write it as:
char **array_of_words
or as:
char *array_of_words[]
This is very similar to the different ways the second parameter to main() can be written.
4I am trying to get a pointer address from a pointer to a pointer array, however I just get garbage when I run the code below. How do I retrieve the pointer address of one of the char * from the char ** array? Thanks for checking this out.
Specifically, I want to obtain the address of "wh" via "what" and assign it to "hi".
char * hi;
char * wh;
char ** what;
int main(void) {
char z[4] = "wx\0";
char a[4] = "ab\0";
hi = &z;
wh = &a;
what = (char **) malloc( 25 * sizeof(char));
what[0] = &hi;
what[1] = &wh;
printf("%s | %s\n", hi, wh);
hi = &what[1];
printf("%s | %s\n", hi, wh);
return EXIT_SUCCESS;
}
Corrected code:
#include <stdio.h>
#include<stdlib.h>
char * hi;
char * wh;
char ** what;
int main(void) {
char z[3] = "wx\0";
char a[3] = "ab\0";
hi = z;
wh = a;
what = malloc(2 * sizeof *what);
what[0] = hi;
what[1] = wh;
printf("%s | %s\n", hi, wh);
hi = what[1];
printf("%s | %s\n", hi, wh);
return 0;
}
The type of hi and wh is not the same as of &z and &a, even though they should yield the same value. Also you want what[1] in hi not the value of the memory location where it is. Also, in C you do not need to cast the return of malloc. However, in C++ the cast is required although its better to use the new operator.
Pointer Assignment
hi and wh are defined as pointer to char. So, change your assignment statements
from,
hi = &z; /* Type of &z is pointer-to-array-of-4-char */
wh = &a; /* Type of &a is pointer-to-array-of-4-char */
to,
hi = z; /* Type of z is pointer-to-char. Array name, here, decays into pointer
to first element of the array */
wh = a; /* Type of a is pointer-to-char */
what is defined as type, pointer to pointer to char. So, change your malloc statement
from,
what = (char **) malloc( 25 * sizeof(char)); /* what needs to hold char*'s,
you have allocated only for char's */
to,
what = malloc(25 * sizeof *what); /* what is of type char**. *what gives you char* */
Also, change your what , hi assignment statements
from,
what[0] = &hi; /* Type of what[0] is pointer-to-char;
Type of &hi is pointer-to-pointer-to-char */
what[1] = &wh; /* Type of what[1] is pointer-to-char;
Type of &wh is pointer-to-pointer-to-char */
...
hi = &what[1]; /* Type of hi is pointer-to-char;
Type of &what[1] is pointer-to-pointer-to-char */
to ,
what[0] = hi; /* Types are same */
what[1] = wh; /* Types are same */
...
hi = what[1]; /* Types are same */
Note:
The size of what is too high than what really required for the posted program. If you feel, you are going to have the same program, modify 25 to 2 in the malloc.
char * hi;
char * wh;
char ** what;
int main(void) {
char z[4] = "wx\0";
char a[4] = "ab\0";
hi = &z;
wh = &a;
First mistake; the types of the expressions &z and &a are both char (*)[4] (pointer to 4-element array of char), not char *. To fix this, drop the & from both:
hi = z;
wh = a;
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize an array, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression is the address of the first element in the array.
what = (char **) malloc( 25 * sizeof(char));
Don't cast the result of malloc; it isn't necessary1, and depending on the compiler version it can suppress a useful diagnostic. You also have a type mismatch. You want to space for 25 pointers to char, but you're only allocating enough for 25 plain chars. Rewrite that as
what = malloc( sizeof *what * 25 );
The type of the expression what is char **; thus, the type of the expression *what is char *. So sizeof *what will give you the same result as sizeof (char *). The above line allocates enough memory to store 25 pointers to char, and assigns the resulting pointer to what.
what[0] = &hi;
what[1] = &wh;
Again, drop the &; hi and wh are already pointers to char:
what[0] = hi;
what[1] = wh;
printf("%s | %s\n", hi, wh);
hi = &what[1];
Type mismatch; &what[1] has type char **, hi has type char *. Again, drop the &.
hi = what[1];
hi and wh now point to the same thing (what[1] == wh and hi == what[1], so hi == wh; that is, both hi and wh contain the same pointer value).
printf("%s | %s\n", hi, wh);
return EXIT_SUCCESS;
}
1. In C, that is; C++ is a different story, but if you're writing C++, you shouldn't be using malloc anyway.
I'm trying to learn C by playing with an Arduino Uno. I'm reviewing the code for the Colorduino library on github. I'm wondering how ++ works when applied to a struct.
There is a PixelRGB struct defined in Colorduino.h:
typedef struct pixelRGB {
unsigned char r;
unsigned char g;
unsigned char b;
} PixelRGB;
In Colorduino.cpp there is a bit of code that applies the ++ operator to a PixelRGB pointer. How does this work?
for (unsigned char y=0;y<ColorduinoScreenWidth;y++) {
for(unsigned char x=0;x<ColorduinoScreenHeight;x++) {
p->r = R;
p->g = G;
p->b = B;
p++;
}
}
Note, that this code increments pointer to PixelRGB, not the struct itself.
So, the result of ++ when applied to pointer, is just incrementing its value by sizeof(PixelRGB)
p is a pointer, not a struct, so it works like pointer arithmetic does on any type. The pointer's value is an address. So when, for example, you add n to a pointer, it's value changes and points to a new address n * sizeof type away. So...
char *p = malloc(SOME_NUMBER * sizeof char);
p++; // p = p + sizeof char
p += 4; // p = p + sizeof char * 4
And if you have a struct...
typedef struct {
int a;
} foo;
/* ... */
foo *fp = malloc(SOME_NUMBER * sizeof foo);
fp++; // fp = fp + sizeof foo;
fp += 4; // fp = fp + sizeof foo * 4;
I asked some time ago on an account I can't remember how to manipulate basic pointers and someone gave me a really good demo
for example
char *ptr = "hello" (hello = a char array)
so now *ptr is pointing at 'h'
ptr++ means moving the ptr to point at the next element, to get its value I do *ptr and that gives me e
ok so far everything works as I hope :D, but now I need to manipulate a char **ptr and was wondering how I do this in a way that mimics the effects of a 2d array?
Some basic tips would be much appreciated as I need to do an assignment that has a **ptr to imitate a 2d array and without knowing how it does this first means I can't even solve it on paper (for example, how do you dereference a **ptr, how do you get [x][y] values etc)
thanks
You can subscript a pointer the same way you can subscript an array, provided all the addresses have been set up correctly.
Assuming the following declaration:
char **ptr;
here are the types of the various expressions:
Expression Type Equivalent expressions (yield same value)
---------- ---- -----------------------------------------
ptr char ** &ptr[0]
*ptr char * ptr[0]
*(ptr+i) char * ptr[i]; &ptr[i][0]
**ptr char ptr[0][0]
*(*(ptr+i)) char ptr[i][0]; *ptr[i]
*(*(ptr+i)+j) char ptr[i][j]
thus:
ptr can be treated as though it was an array of strings (2-d array of char)
ptr[i] points to the beginning of the i'th string in the list
ptr[i][j] is the value of the j'th character of the i'th string in the list
The expressions ptr++ and ++ptr will advance ptr to point to the next string
The expressions (*ptr)++ and ++(*ptr) will advance *ptr to point to the next character
As for setting up your pointers, this arrangement assumes everything has already been allocated as static arrays or dynamically through malloc. You cannot just write
char **ptr = {"foo", "bar", "bletch"}; // using aggregate initializer on
// non-aggregate type; bad juju,
// a.k.a undefined behavior
or
char **ptr; // ptr has not been initialized to point anywhere
ptr[0] = "foo"; // dereferencing ptr via subscript invokes undefined
ptr[1] = "bar"; // behavior
ptr[2] = "bletch";
Generally, when you're using a pointer as though it was an array, you'll use malloc or something similar to allocate your buffers:
char **ptr = malloc(sizeof *ptr * N);
if (ptr)
{
ptr[0] = "foo"; // ptr[i] gets address of
ptr[1] = "bar"; // string literal
ptr[2] = "bletch";
...
}
or
char **ptr = malloc(sizeof *ptr * N);
if (ptr)
{
size_t i;
for (i = 0; i < N; i++)
{
ptr[i] = malloc(sizeof *ptr[i] * M); // strictly speaking, the sizeof
if (ptr[i]) // is not necessary here
{
//initialize ptr[i]
}
}
}
A pointer to a pointer is just that. For example:
// Declare our double-indirection pointer.
char** ptr;
// And initialize it:
char s1[] = "hello";
char s2[] = "world";
ptr = malloc(sizeof(char*) * 2);
ptr[0] = s1;
ptr[1] = s2;
// ptr now points to a pointer that points to 'h'.
char* ptr2 = *ptr;
// ptr2 points to 'h'.
char* ptr3 = *(ptr + 1);
// ptr3 points to "w".
char c = **ptr; // could be written as *(*ptr)
// c = 'h'.
char c2 = *(*(ptr + 1));
// c2 = 'w'.
char c3 = *(*(ptr) + 1);
// c3 = 'e'.
You may use them as you would a normal two-dimensional array. (Since effectively, that's what they are)
char** ptr = {"lorem", "ipsum", "dolor"};
char* s1 = ptr[0]; //Points to the beginning of "lorem"
char* s2 = ptr[1]; //Points to the beginning of "ipsum"
char c = ptr[2][4]; //Contains 'r'
This is due to the fact that:
int *a;
//...
int i = a[6];
int j = *(a + 6); //Same as previous line!
Cheers,
Amit Ron--