What the difference between these two C-declaration in memory? - arrays

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.

Related

How to reverse every string in an array of strings through a function in C?

I have been trying to solve this issue for whole day, and could not do it on my own. Searching the internet didn't help me solve it either
So, this the function prototype:
void invert(char **arr, int n);
First argument is an array of strings, and the second one is number of strings in an array.
This is my code:
#include <stdio.h>
#include <string.h>
void invert(char** arr, int n)
{
int i, j, len;
for(j=0;j<n;j++)
{
len=strlen(arr[j]);
for(i=0;i<len/2;i++)
{
char tmp = arr[j][i];
arr[j][i] = arr[j][len - i - 1];
arr[j][len - i - 1] = tmp;
}
}
}
int main()
{
int n=3, i;
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
invert(arr, n);
for(i=0;i<3;i++)
{
printf("%s ",arr[i]);
}
}
The code breaks when it reaches the line:
arr[j][i] = arr[j][len - i - 1];
and I can't figure out why.
The function receives an array of strings perfectly (tested it with some printf statements for characters of specific strings), and the char tmp succesfully recieves a correct character, but the program crashed when it reaches the line mentioned earlier. Printf statements after that line don't work.
Did I miss anything? Can someone explain what am I doing wrong? Thank you!
For starters this code snippet
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
invokes undefined behavior because the pointer arr is uninitialized and has an indeterminate value.
Moreover this approach in any case is wrong because you may not change string literals.
What you need is to declare a two-dimensional array as for example
enum { N = 11 };
//...
char arr[3][N] =
{
"John", "Doe", "Programmer"
};
In this case the function declaration will look like
void invert( char arr[][N], int n );
The enumeration must be declared before the function declaration.
Instead of the two-dimensional array you could declare an array of pointers like
char s1[] = "John";
char s2[] = "Doe";
char s3[] = "Programmer";
char * arr[3] = { s1, s2, s3 };
In this case the function declaration may be as shown in your question
void invert(char** arr, int n)
So what you need to do with minimal changes is to substitute this code snippet
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
for this code snippet
char s1[] = "John";
char s2[] = "Doe";
char s3[] = "Programmer";
char * arr[3] = { s1, s2, s3 };
To begin with, what you have here:
char **arr;
is a pointer to pointer to char.
Secondly, even if you had an array of pointers to char, like so :
char *arr[3];
And then assigning each string literal :
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
would still invoke Undefined behavior, since you are attempting to modify a string literal which is read only.
What you need is, either a 2D array of chars :
char arr[][100] = {"John", "Doe", "Programmer"};
and also change the function signature to :
void invert(char arr[][100], int n)
or you have to dynamically allocate memory and use a function like strcpy(), strdup(), memcpy() etc :
char **arr;
arr = malloc(n * sizeof(char *)); // or sizeof(*arr)
if (arr == NULL) {
fprintf(stderr, "Malloc failed to allocate memory\n");
exit(1);
}
arr[0] = strdup("John"); // good idea to also check if strdup returned null
arr[1] = strdup("Doe");
arr[2] = strdup("Programmer");
invert(arr, n);
for(i=0;i<3;i++)
{
printf("%s ",arr[i]);
}
for (i = 0; i < 3; i++) {
free(arr[i]);
}
free(arr);

What does char **text = (char **) malloc(n * sizeof(char*)); does?

i just started with programming and i don't know what does this mean ..
I tried everything i could..
I know its dynamic memory allocation but don't know what all these (stars) means.
Could someone explain me, what every type is?
This is the code:
char **text = (char **) malloc(n * sizeof(char*));
text[i] = (char *) malloc(MAX_LENG);
The code allocates (dynamic) memory for holding n strings. Each of these strings with max length MAX_LENG - 1.
I assume the complete original code to be:
char **text = (char **) malloc(n * sizeof(char*));
for (int i = 0; i < n; ++i)
text[i] = (char *) malloc(MAX_LENG);
or without the unnecessary casts:
char **text = malloc(n * sizeof(char*));
for (int i = 0; i < n; ++i)
text[i] = malloc(MAX_LENG);
So the first line, i.e.
char **text = malloc(n * sizeof(char*));
will give you a pointer to a memory area holding n pointers-to-char
The loop, i.e.
for (int i = 0; i < n; ++i)
text[i] = malloc(MAX_LENG);
then makes each of these n pointers point to a memory area with MAX_LENG chars.
It looks like:
So after this you have memory for n strings and can use them like:
strcpy(text[0], "HELLO"); // First string is "Hello"
strcpy(text[1], "WORLD"); // Second string is "World"
After this it looks like:
You can access the individual charaters like this
char c = text[1][4]; // c now holds the character 'D' from the string "WORLD"
A simple explanation can look the following way. Let's assume that you have an array of pointers to string literals. For example
char * s[] = { "Hello ", "World!" };
The array designator used in expression with rare exception is converted to pointer to its first element. So the array designator s in most cases is converted to pointer of the type char **. That is it is a pointer to an object of the type char *.
For example
char **p = s;
Dereferencing the pointer you will get the first element of the array that in turn has the type char *. For example
#include <stdio.h>
int main( void )
{
enum { N = 2 };
char * s[N] = { "Hello ", "World!" };
for ( char **p = s; p != s + N; ++p )
{
printf( "%s", *p );
}
putchar( '\n' );
return 0;
}
The program output is
Hello World!
Now let's assume that you want to allocate the array s dynamically. The array has N element of the type char *.
So you need to write the expression
malloc( N * sizeof( char * ) )
The function call return pointer to the start of the allocated extent of memory where there will be the first element of the type char *. That is the function returns a pointer of the type void * to potentially the first element of the dynamically allocated array.
So you need to write
char **p = malloc( N * sizeof( char * ) );
or
char **p = ( char ** )malloc( N * sizeof( char * ) );
It is similar to the declaration shown above
char **p = s;
Other answers explained what it does but I want to focus on one small detail.
char **text = malloc(n * sizeof(char*));
Using the types instead of objects in sizeof is considered as a not good practice. Why? If you change the type of the object you need to change all possible appearances of the old type. If you use the object in the sizeof - every sizeof will be calculated correctly without any changes in the code.
char **text = malloc(n * sizeof(*text));

Reverse String with a pointer to a function, which executes the String reverse

I would like to reverse a String with an pointer to a function, which executes the String reverse.
I have the feeling that I did not grasp the concept of using pointer to variables or functions correctly, so I would be very thankful if someone could expain me, where I am thinking wrong here:
1) Define a pointer to a function:
char *strrev(char *str)
{
char *p1, *p2;
if (! str || ! *str)
return str;
for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
{
*p1 ^= *p2;
*p2 ^= *p1;
*p1 ^= *p2;
}
return str;
}
2) Now in my main I define a pointer, which matches the function I defined above:
int main(void) {
char (*functPtr)(char);
functPtr = &strrev;
3) Now I define the String, which I want to reverse, define a new pointer and let the pointer point to the address space of the String.
char str[50] = "Hello, World";
char *pointer[50];
pointer[50] = &str[50];
4) Lastly I define a new String and write the result of the function, which call through the pointer, which points to the pointer to the function.
char t[50] = (*functPtr)(pointer[50]);
printf("%s\n", str);
return(0);
}
Unfortunaly I get all kinds of error message such as:
Ü1.c:29:10: error: array initializer must be an initializer list or string literal
char t[50] = (*functPtr)(pointer[50]);
^
Ü1.c:27:5: warning: array index 50 is past the end of the array (which contains 50 elements) [-Warray-bounds]
pointer[50] = &str[50];
^ ~~
Ü1.c:26:5: note: array 'pointer' declared here
char *pointer[50];
^
Ü1.c:29:30: warning: array index 50 is past the end of the array (which contains 50 elements) [-Warray-bounds]
char t[50] = (*functPtr)(pointer[50]);
^ ~~
Ü1.c:26:5: note: array 'pointer' declared here
char *pointer[50];
^
2 warnings and 1 error generated.
1) Define a pointer to a function:
No, you did not define a pointer to function. You defined a function with the name strrev.
2) Now in my main I define a pointer, which matches the function I
defined above:
int main(void) {
char *(*functPtr)(char *);
functPtr = &strrev;
Yes, you defined a pointer to function and initialized it with the address of the function strrev. As function designators used in expressions are implicitly converted to pointers to function then you could write
int main(void) {
char *(*functPtr)(char *);
functPtr = strrev;
3) Now I define the String, which I want to reverse, define a new
pointer and let the pointer point to the address space of the String.
char str[50] = "Hello, World";
char *pointer[50];
pointer[50] = &str[50];
Except the definition of the character array that contains a string all other records do not make any sense. For starters the function strrev reverses a string in place. It does not create a reversed copy of the passed to it string.
If you want to declare a pointer that will get the address of the reversed string returned by the function that equal to the address of the original string then you could just write
char *pointer = functPtr( str );
4) Lastly I define a new String and write the result of the function,
which call through the pointer, which points to the pointer to the
function.
char t[50] = (*functPtr)(pointer[50]);
printf("%s\n", str);
You already defined a pointer that will get the value returned from the function. So there is no sense to declare one more array. Moreover arrays do not have the assignment operator. And the function reversed the original string in place. Why are you going to create one more array with the duplicate copy of the original reversed string?! This entirely does not make a sense.
Your program can look the following way
#include <stdio.h>
#include <string.h>
char * strrev( char *s )
{
size_t n = strlen( s );
if ( n )
{
for ( char *first = s, *last = s + n; first < --last; ++first )
{
char c = *first;
*first = *last;
*last = c;
}
}
return s;
}
int main(void)
{
char * ( *fp )( char * ) = strrev;
char s[] = "Hello, World";
puts( s );
puts( fp( s ) );
return 0;
}
The program output is
Hello, World
dlroW ,olleH
If you initially wanted that the function would not reverse the original string but make a reversed copy of the original string then in this case indeed there is a sense to define one additional character array that will get the reversed copy of the original string.
In this case the program can look like.
#include <stdio.h>
#include <string.h>
char *reverse_copy( char *s1, const char *s2 )
{
*( s1 += strlen( s2 ) ) = '\0';
while (*s2)
{
*--s1 = *s2++;
}
return s1;
}
int main(void)
{
char * ( *fp )( char *, const char * ) = reverse_copy;
char s[] = "Hello, World";
char t[sizeof( s )];
puts( s );
puts( fp( t, s ) );
return 0;
}
The program output is
Hello, World
dlroW ,olleH
Now the original character array s was not changed while the array t got the reversed copy of the original string stored in the array s.
I summarize my comments in this answer, as it gives more space for details of the comments.
char (*functPtr)(char); should be char *(*functPtr)(char *); as it takes a pointer to a char, not a char. Likewise it returns a pointer.
char *pointer[50]; would be an array of 50 pointers, You want to say "a pointer to an array of 50 chars". In C we don't say that. We just say "a pointer to a char" and don't say how many. So char *pointer; would be enough.
char t[50] = (*functPtr)(pointer[50]); is not correct in C.
You want to assign the result of funcPtr to the array t. But here you mix initialization with assignment.
char t[50]; declares an array of 50 chars. You can initialize it by giving it a value, for example char t[50] = "Hello World"; which will have the compiler copy "Hello World" to the array.
But you try to assign the function pointer to the array. You probably intend to put the result of the function into the array.
Note also that you cannot "assign" an array to another array. You can only copy it.
So the correct code would be:
char *(*functPtr)(char *);
functPtr = &strrev;
char str[50] = "Hello, World";
char t[50];
char *s= funcPtr(str); // call the function and save the returned pointer
strcpy(t, s); // now copy the result to your array.
printf("%s\n", t); // and print it
Note: char str[50] = "Hello, World"; is correct and, just so you'll know, char *str = "Hello, World"; is wrong. Why? Because the second str will point to read-only memory (a "string literal") and any attempt to modify it would abort the program. But here you did it right.

How to use several pointers to one twodimensional array in c?

I want to create pointers on array in c. For example, I have an array
char arr1[4][20];
I want to make pointers and these pointers would get memory like this pointer p = arr1[0][0-20]
t = arr1[1][0-20], u = arr[1][0-20]. I want to keep all strings from different files in one array.
I try to do something like that, but it's not working.
char name[20][20];
char *s[20];
char *t[20];
s = name[1];
t = name[2];
An array declared like this
char name[20][20];
used in expressions as for example an initializer is implicitly converted to pointer to its firs element that is has the type char ( * )[20].
So you may write for example
char ( *s )[20] = name;
In this case for example to traverse character elements of the array pointed to by the pointer s you need to use expressions like
( *s )[0], ( *s )[1], an so on
Or like
s[0][0], s[0][1], and so on.
It will be simpler to traverse pointed character arrays if pointer would be declared like
char *s = name[0];
char *t = name[1];
and so on.
So either you should declare pointers like
char ( *s )[20] = name;
char ( *t )[20] = name + 1;
or like
char *s = name[0];
char *t = name[1];
Here's how you declare a pointer to an array of 20 elements:
char (*ptr)[20];
So, this is how you do what you want to do:
char name[20][20];
char (*s)[20] = &name[1]; // note the &
char (*t)[20] = &name[2];
And here's how you access elements of those arrays later on:
for (size_t i = 0; i < sizeof(*s); ++i) {
printf("%d ", (*s)[i]);
}
You can round out you question with a short exercise putting the pointer assignments to use. For example continuing from the comment above, with the creation of myptr as a pointer-to-aray of char[20] and s and t to an array of char[20], you could do:
#include <stdio.h>
int main (void) {
const char name[20][20] = { "Mickey Mouse", "Minnie Mouse", "Pluto",
"Bugs Bunny", "Porky Pig", "Daffy Duck", "" },
(*myptr)[20] = name;
while (1) {
const char *s = *myptr++, *t = *myptr++;
if (*s)
puts (s);
else
break;
if (*t)
puts (t);
else
break;
}
}
Example Use/Output
$ ./bin/ptr2arrexercise
Mickey Mouse
Minnie Mouse
Pluto
Bugs Bunny
Porky Pig
Daffy Duck
Question: What purpose does the empty-string serve as the last element of name in the code above?

C - 'char **' differs in levels of indirection from 'char (*)[6]'

Can someone please explain to me what's wrong with the following, and more importantly why?
int main( int argc, char *argv[] )
{
char array[] = "array";
char **test;
test = &array;
*test[0] = 'Z';
printf( "%s\n", array );
return 0;
}
EDIT
My example above was based on a function like this that was crashing:
void apple( char **pp )
{
*pp = malloc( 123 );
*pp[0] = 'a'; // technically this is correct but in bad form
*pp[1] = 'b'; // incorrect but no crash
*pp[2] = '\0'; // incorrect and crash
}
As pointed out to me by Vaughn Cato although *pp[0] = 'a'; does not crash it is in bad form. The correct form is the parenthesis
void apple( char **pp )
{
*pp = malloc( 123 );
(*pp)[0] = 'a'; // correct
(*pp)[1] = 'b'; // correct
(*pp)[2] = '\0'; // correct
}
Also as another poster MK pointed out the FAQ covers the difference between arrays and pointers:
http://www.lysator.liu.se/c/c-faq/c-2.html
test = &array
is wrong because test is of type char** and &array is a char(*)[6] and is a different type from char**
An array isn't the same type as char* although C will implicitly convert between an array type and a char* in some contexts, but this isn't one of them. Basically the expectation that char* is the same as the type of an array (e.g: char[6]) is wrong and therefore the expectation that taking the address of an array will result in a char** is also wrong.
This would be the way to do what you seem to be trying to do:
int main( int argc, char *argv[] )
{
char array[] = "array";
char (*test)[6];
test = &array;
(*test)[0] = 'Z';
printf( "%s\n", array );
return 0;
}
test is a pointer to an array, and an array is different from a pointer, even though C makes it easy to use one like the other in my cases.
If you wanted to avoid having to specify a specific sized array, you could use a different approach:
int main( int argc, char *argv[] )
{
char array[] = "array";
char *test;
test = array; // same as test = &array[0];
test[0] = 'Z';
printf( "%s\n", array );
return 0;
}
char **test; is a pointer to a pointer, but if you're going to take the address of an entire array then it needs to be a pointer to entire array i.e char (*test)[6];

Resources