Passing array of pointers to a function accepting 2d array - arrays

I have the following code in C
#include <stdio.h>
char *gstr[] = { "Hello", "World" };
void func(char str[][8]) {
printf("%p\n", (void *)str);
printf("%p\n", (void *)(str + 1));
printf("%s\n", *(str + 1));
}
int main(void) {
printf("%p\n", (void *)gstr);
printf("%p\n", (void *)(gstr + 1));
printf("%s\n", *(gstr + 1));
printf("Calling Function\n");
func(gstr);
return 0;
}
The following is the output
0x556f11ddd010
0x556f11ddd018
World
Calling Function
0x556f11ddd010
0x556f11ddd018
$��oU
I cannot understand why printf("%s\n", *(str+1)); in the function func does not print the string world.

char *gstr[] = {"Hello", "World"}; declares gstr to be an array of pointers to char.
By itself, char str[][8] declares str to be an array of arrays of eight char. However, as a function parameter, it is automatically adjusted from an array to a pointer: It declares str to be a pointer to an array of eight char.
A pointer to an array is different from an array of pointers.
Your compiler should have warned you that the type of gstr in func(gstr) is incompatible with the type of the parameter in void func(char str[][8]). Pay attention to the messages from your compiler.
To pass gstr to func correctly, change the declaration of func to func(char *str[]) or the equivalent func(char **str).
func(gstr) passes the address of the first element of gstr to the function. Since gstr is an array of pointers, the address of its first element is the address of a pointer (that being a pointer to the first character of "Hello").
In func, the function expects a pointer to an array of eight char. If it uses the address it is given for that, it is pointing to a pointer instead of an array of eight char. Passing that to printf attempts to print the bytes representing the pointer as if they were a string of characters.

You can compile the code below to see the output.
#include <stdio.h>
char *gstr[] = {"Hello", "World"};
void func(char str[][8]) {
printf("%p\n", (void*) str);
printf("%p\n", (void*) *str);
printf("%p\n", (void*) (str+1));
printf("%p\n", (void*) *(str+1));
printf("%s\n", *(str+1));
}
int main(void) {
printf("%p\n", (void *) gstr);
printf("%p\n", (void *) *gstr);
printf("%p\n", (void*) (gstr+1));
printf("%p\n", (void*) *(gstr+1));
printf("%s\n", *(gstr+1));
printf("Calling Function\n");
func(gstr);
return 0;
}
0x100402010
0x100403000
0x100402018
0x100403006
World
Calling Function
0x100402010
0x100402010
0x100402018
0x100402018
0#
The compiler know that gstr is an array of pointers, so that in function main, the object at gstr + 1 will be interpreted as char* and you get the expected result.
However in function func, the bytes at str + 1 will be interpreted as char [8], and you know it will return the first address of this object which is str+1

Related

converting a string to a void pointer

I'm trying to figure out how to "transform" strings (char*) to void* and viceversa.
When I execute this my output is just the first printf and ignores the second one, it doesn't even write "after = "
PS This little program is just to understand, I know i could actually use swap(&s[0],&s[1]). I need to know how to properly cast a void pointer into an array of strings.
I'm working on a uni project where I need to create my own quick_sort algorythm and I need the swap function inside of it to work with void pointers.
#include <stdio.h>
#include <stdlib.h>
static void swap(char** x,char** y);
static void swap(char** x,char** y){
char* temp=*x;
*x=*y;
*y=temp;
}
int main()
{
char* s[2];
s[0]="weee";
s[1]="yooo";
void* array=s;
printf("before %s %s\n",s[0],s[1]);
swap((&array)[0],(&array)[1]);
printf("after = %s %s",(char*)array,(char*)array);
return 0;
}
I think I'm missing something big
Thanks in advance :D
In this declaration the array s used as an initializer is implicitly converted to a pointer to its first element of the type char **.
void* array = s;
In the call of the function swap
swap((&array)[0],(&array)[1]);
the first argument can be the pointer array itself that will be implicitly casted to the pointer type of the corresponding parameter
swap( array, (&array)[1]);
But you need to correctly pass the second argument. To do this you need to cast the pointer array explicitly like
swap( array, ( char ** )array + 1 );
In the call of printf you need also correctly to supply argument expressions.
Here is your updated program
#include <stdio.h>
static void swap(char** x,char** y);
static void swap(char** x,char** y){
char* temp=*x;
*x=*y;
*y=temp;
}
int main()
{
char* s[2];
s[0]="weee";
s[1]="yooo";
void* array=s;
printf("before %s %s\n",s[0],s[1]);
swap( array, ( char ** )array + 1 );
printf("after = %s %s", *(char**)array, ( (char**)array )[1]);
return 0;
}
The program output is
before weee yooo
after = yooo weee
void *array = s; declares array to be a void *. Then &array is the address of that void *, so &array[1] would access a void * after it. But there is no void * after it, since void *array defines a single void *.
array could be properly defined to alias s with char **array = s;, after which swap(&array[0], &array[1]); would work as desired.
If you define array as void **array = (void **) s;, then swap(&array[0], &array[1]); will produce diagnostic messages because the types are wrong. You could use swap((char **) &array[0], (char **) &array[1]);.
Then, if you print the strings with printf("after = %s %s", array[0], array[1]);, this will work, although it is not entirely proper code. Using array[0] as an argument passes a void * where printf is expecting a char * for the %s. However, the C standard guarantees that void * and char * have the same representation (encode their values using bytes in memory in the same way), and it further says (in a non-normative note) that this is intended to imply interchangeability as arguments to functions.
The void* doesn't seem to fulfil any particular purpose here, just swap the pointers: swap(&s[0],&s[1]);.
You could also do this:
char** ptr = &s[0];
printf("before %s %s\n",ptr[0],ptr[1]);
swap(&ptr[0],&ptr[1]);
printf("after = %s %s",ptr[0],ptr[1]);
If you for reasons unknown insist on using void* then note that as your code stands, it points at the first char* in your array of char*. However, it isn't possible to perform pointer arithmetic on void* since that would entail knowing how large a "void" is. The void* doesn't know that it points at an array of pointers. Therefore array[i] is nonsense.
Also, the void* are set to point at char* so you simply cannot pass it to a function expecting a char**. You'd have to rewrite the whole program in a needlessly obfuscated way, so just abandon that idea.

Why can't I access a pointer to pointer for a stack array?

Please take a look at the following code. It tries to pass an array as a char** to a function:
#include <stdio.h>
#include <stdlib.h>
static void printchar(char **x)
{
printf("Test: %c\n", (*x)[0]);
}
int main(int argc, char *argv[])
{
char test[256];
char *test2 = malloc(256);
test[0] = 'B';
test2[0] = 'A';
printchar(&test2); // works
printchar((char **) &test); // crashes because *x in printchar() has an invalid pointer
free(test2);
return 0;
}
The fact that I can only get it to compile by explicitly casting &test2 to char** already hints that this code is wrong.
Still, I'm wondering what exactly is wrong about it. I can pass a pointer to a pointer to a dynamically allocated array but I can't pass a pointer to a pointer for an array on the stack. Of course, I can easily work-around the problem by first assigning the array to a temporary variable, like so:
char test[256];
char *tmp = test;
test[0] = 'B';
printchar(&tmp);
Still, can someone explain to me why it doesn't work to cast char[256] to char** directly?
test is an array, not a pointer, and &test is a pointer to the array. It is not a pointer to a pointer.
You may have been told that an array is a pointer, but this is incorrect. The name of an array is a name of the entire object—all the elements. It is not a pointer to the first element. In most expressions, an array is automatically converted to a pointer to its first element. That is a convenience that is often useful. But there are three exceptions to this rule:
The array is the operand of sizeof.
The array is the operand of &.
The array is a string literal used to initialize an array.
In &test, the array is the operand of &, so the automatic conversion does not occur. The result of &test is a pointer to an array of 256 char, which has type char (*)[256], not char **.
To get a pointer to a pointer to char from test, you would first need to make a pointer to char. For example:
char *p = test; // Automatic conversion of test to &test[0] occurs.
printchar(&p); // Passes a pointer to a pointer to char.
Another way to think about this is to realize that test names the entire object—the whole array of 256 char. It does not name a pointer, so, in &test, there is no pointer whose address can be taken, so this cannot produce a char **. In order to create a char **, you must first have a char *.
Because test is not a pointer.
&test gets you a pointer to the array, of type char (*)[256], which is not compatible with char** (because an array is not a pointer). This results in undefined behavior.
The type of test2 is char *. So, the type of &test2 will be char ** which is compatible with the type of parameter x of printchar().
The type of test is char [256]. So, the type of &test will be char (*)[256] which is not compatible with the type of parameter x of printchar().
Let me show you the difference in terms of addresses of test and test2.
#include <stdio.h>
#include <stdlib.h>
static void printchar(char **x)
{
printf("x = %p\n", (void*)x);
printf("*x = %p\n", (void*)(*x));
printf("Test: %c\n", (*x)[0]);
}
int main(int argc, char *argv[])
{
char test[256];
char *test2 = malloc(256);
test[0] = 'B';
test2[0] = 'A';
printf ("test2 : %p\n", (void*)test2);
printf ("&test2 : %p\n", (void*)&test2);
printf ("&test2[0] : %p\n", (void*)&test2[0]);
printchar(&test2); // works
printf ("\n");
printf ("test : %p\n", (void*)test);
printf ("&test : %p\n", (void*)&test);
printf ("&test[0] : %p\n", (void*)&test[0]);
// Commenting below statement
//printchar((char **) &test); // crashes because *x in printchar() has an invalid pointer
free(test2);
return 0;
}
Output:
$ ./a.out
test2 : 0x7fe974c02970
&test2 : 0x7ffee82eb9e8
&test2[0] : 0x7fe974c02970
x = 0x7ffee82eb9e8
*x = 0x7fe974c02970
Test: A
test : 0x7ffee82eba00
&test : 0x7ffee82eba00
&test[0] : 0x7ffee82eba00
Point to note here:
The output (memory address) of test2 and &test2[0] is numerically same and their type is also same which is char *.
But the test2 and &test2 are different addresses and their type is also different.
The type of test2 is char *.
The type of &test2 is char **.
x = &test2
*x = test2
(*x)[0] = test2[0]
The output (memory address) of test, &test and &test[0] is numerically same but their type is different.
The type of test is char [256].
The type of &test is char (*) [256].
The type of &test[0] is char *.
As the output shows &test is same as &test[0].
x = &test[0]
*x = test[0] //first element of test array which is 'B'
(*x)[0] = ('B')[0] // Not a valid statement
Hence you are getting segmentation fault.
You cannot access a pointer to a pointer because &test is not a pointer—it's an array.
If you take the address of an array, cast the array and the address of the array to (void *), and compare them, they will (barring possible pointer pedantry) be equivalent.
What you're really doing is similar to this (again, barring strict aliasing):
putchar(**(char **)test);
which is quite obviously wrong.
Your code expects the argument x of printchar to point to memory that contains a (char *).
In the first call, it points to the storage used for test2 and is thus indeed a value that points to a (char *), the latter pointing to the allocated memory.
In the second call, however, there is no place where any such (char *) value might be stored and so it is impossible to point to such memory. The cast to (char **) you added would have removed a compilation error (about converting (char *) to (char **)) but it would not make storage appear out of thin air to contain a (char *) initialized to point to the first characters of test. Pointer casting in C does not change the actual value of the pointer.
In order to get what you want, you have to do it explicitly:
char *tempptr = &temp;
printchar(&tempptr);
I assume your example is a distillation of a much larger piece of code; as an example, perhaps you want printchar to increment the (char *) value that the passed x value points to so that on the next call the next character is printed. If that isn't the case, why don't you just pass a (char *) pointing to the character to be printed, or even just pass the character itself?
Apparently, taking the address of test is the same as taking the address of test[0]:
#include <stdio.h>
#include <stdlib.h>
static void printchar(char **x)
{
printf("[printchar] Address of pointer to pointer: %p\n", (void *)x);
printf("[printchar] Address of pointer: %p\n", (void *)*x);
printf("Test: %c\n", **x);
}
int main(int argc, char *argv[])
{
char test[256];
char *test2 = malloc(256);
printf("[main] Address of test: %p\n", (void *)test);
printf("[main] Address of the address of test: %p\n", (void *)&test);
printf("[main] Address of test2: %p\n", (void *)test2);
printf("[main] Address of the address of test2: %p\n", (void *)&test2);
test[0] = 'B';
test2[0] = 'A';
printchar(&test2); // works
printchar(&test); // crashes because *x in printchar() has an invalid pointer
free(test2);
return 0;
}
Compile that and run:
forcebru$ clang test.c -Wall && ./a.out
test.c:25:15: warning: incompatible pointer types passing 'char (*)[256]' to
parameter of type 'char **' [-Wincompatible-pointer-types]
printchar(&test); // crashes because *x in printchar() has an inva...
^~~~~
test.c:4:30: note: passing argument to parameter 'x' here
static void printchar(char **x)
^
1 warning generated.
[main] Address of test: 0x7ffeeed039c0
[main] Address of the address of test: 0x7ffeeed039c0 [THIS IS A PROBLEM]
[main] Address of test2: 0x7fbe20c02aa0
[main] Address of the address of test2: 0x7ffeeed039a8
[printchar] Address of pointer to pointer: 0x7ffeeed039a8
[printchar] Address of pointer: 0x7fbe20c02aa0
Test: A
[printchar] Address of pointer to pointer: 0x7ffeeed039c0
[printchar] Address of pointer: 0x42 [THIS IS THE ASCII CODE OF 'B' in test[0] = 'B';]
Segmentation fault: 11
So the ultimate cause of the segmentation fault is that this program will try to dereference the absolute address 0x42 (also known as 'B'), which your program doesn't have permission to read.
Although with a different compiler/machine the addresses will be different: Try it online!, but you'll still get this, for some reason:
[main] Address of test: 0x7ffd4891b080
[main] Address of the address of test: 0x7ffd4891b080 [SAME ADDRESS!]
But the address that causes the segmentation fault may very well be different:
[printchar] Address of pointer to pointer: 0x7ffd4891b080
[printchar] Address of pointer: 0x9c000000942 [WAS 0x42 IN MY CASE]
The representation of char [256] is implementation dependent. It is must not be the same as char *.
Casting &test of type char (*)[256] to char ** yields undefined behavior.
With some compilers, it may do what you expect, an on others not.
EDIT:
After testing with gcc 9.2.1, it appears that printchar((char**)&test) passes in fact test as value cast to char**. It is as if the instruction was printchar((char**)test). In the printchar function, x is a pointer to the first char of the array test, not a double pointer to the first character. A double de-reference x result in a segmentation fault because the 8 first bytes of the array do not correspond to a valid address.
I get the exact same behavior and result when compiling the program with clang 9.0.0-2.
This may be considered as a compiler bug, or the result of an undefined behavior whose result might be compiler specific.
Another unexpected behavior is that the code
void printchar2(char (*x)[256]) {
printf("px: %p\n", *x);
printf("x: %p\n", x);
printf("c: %c\n", **x);
}
The output is
px: 0x7ffd92627370
x: 0x7ffd92627370
c: A
The weird behavior is that x and *x have the same value.
This is a compiler thing. I doubt that this is defined by the language.

Passing a 2D array to a function taking a pointer

#include <stdio.h>
void func(int **);
int main(void)
{
int ptr[2][3] = { {8, 7, 3}, {4, 5, 6} };
printf("ptr point is %p\n", ptr);
printf("*ptr point is %p\n", *ptr);
func(ptr);
system("pause");
return 0;
}
void func(int *ptr[8])
{
printf("ptr point is %p\n", ptr);
printf("*ptr point is %p\n", *ptr);
printf("*(ptr + 1) point is %p\n", *(ptr + 1));
}
Output:
ptr point is 004FFC24
*ptr point is 004FFC24
ptr point is 004FFC24
*ptr point is 00000008
*(ptr + 1) point is 00000007
Press any key to continue
Why ptr now becomes a 1D pointer?
As you can see
*(ptr) in func() output a 8;
*(ptr + 1) in func() output a 7;they are all digits in the array,
However, ptr should be 2D pointer, (because [] match with *, consequently *ptr[8] should match with **ptr).
so *(ptr + 1) and *(ptr) should be 1D pointers, instead of digits?
You have several issues.
First, you declare func to take a char **, but later define it to take int *[8], which doesn’t match. Even worse, both are wrong - or rather, they don’t match the type of the argument you’re passing.
Except when it is the operand of the sizeof or unary & operators, an expression of type “N-element of T” will be converted (“decay”) to an expression of type “pointer to T”, and the value of the expression will be the address of the first element.
When you pass ptr to func, it is converted from type “2-element array of 3-element array of int” to “pointer to 3-element array of int”, or int (*)[3]. So the function prototype needs to be
void func( int (*ptr)[3] )
or
void func( int ptr[][3] )
Because your function definition and declarations don’t match, and because neither matches the actual type of the argument, you get the unexpected output. You should have gotten a warning on the mismatched function argument types; if not, you may need to raise the warning level.

Memory addresses of stack

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
struct s1 {
char *z;
int i;
struct s1 *p;
};
struct s1 *ptr;
static struct s1 a[] = {
{"Nagpur", 1, a + 1},
{"Raipur", 2, a + 2},
{"Kanpur", 3, a}
};
ptr = a;
printf("%p\n", a[0]);
printf("%p\n", a[1]);
printf("%p\n", a[2]);
printf("%p\n", ptr);
printf("%p\n", a[2].p);
printf("%p\n", a[1].p->p);
printf("%p\n", a);
return EXIT_SUCCESS;
}
Whenever we have an array, suppose we call it a[10], then the address of a or a[0] are equal. But in the above case, the address of a and that of a[0] is different. I can't figure out why?
What you're passing to printf() here is the structure itself, not a pointer to it:
printf("%p\n", a[0]);
The behavior of this code is poorly defined. (In practice, it will typically end up printing the first element of the structure, but this may not be consistent.) What you probably want is:
printf("%p\n", &a[0]);
^
If you had compiled with warnings enabled (e.g. gcc -Wall -Werror), you would see that this line:
printf("%p\n", a[0]);
is invalid:
ptr.c:20:5: error: format ‘%p’ expects argument of type ‘void *’, but
argument 2 has type ‘struct s1’ [-Werror=format=]
printf("%p\n", a[0]);
^
You're taking the 0th element of that structure, or in other words, dereferencing a, and passing a struct s1 by value to printf, who is doing like you said, and interpreting it as a pointer.
If you instead take the address of the first element of the array, you'll see that they are indeed, at the same address:
printf("%p\n", &a[0]);
The reason why both are different is when you print a, its just reference, whereas a[0] is used to de-reference. Try printf("%p\n",&a[0]).
the printf() calls with the a[x] parameter will not print addresses but rather the contents of that offset. This line segment: 'then the address of a or a[0] are equal' is not true. However, then the address of a and the address of a[0] are equal is true. The '%p' format converter is only for addresses. so the code needs to use addresses, not the contents.
suggest using something like:
printf("%p\n", &a[0]);
printf("%p\n", &a[1]);
printf("%p\n", &a[2]);
printf("%p\n", ptr);
printf("%p\n", a[2].p);
printf("%p\n", a[1].p->p);
printf("%p\n", a);
you are assigning addresses of strings (e.g. "nagpur") char pointer. these strings will be present in code section. so "z" will be having addresses of those strings and you are trying to print those by printing a[0]. you should print &a[0] instead. a[0] is similar operation to *(a+0). so if you want to print its address you should use & operator.

Passing arrays in c

I have a question regarding passing arrays in c to a function.
When I run this program it gives me a segmentation fault
int main()
{
char **ptr= NULL;
test(ptr);
printf("%s", ptr[0]);
return 0;
}
void test(char **ptr)
{
ptr = (char **) malloc(sizeof(char *));
ptr[0] = (char *) malloc(sizeof(char)*5);
strcpy(ptr[0], "abc");
return;
}
but this worked just fine
int main()
{
char **ptr= NULL;
test(&ptr);
printf("%s", ptr[0]);
return 0;
}
void test(char ***ptr)
{
*ptr = (char **) malloc(sizeof(char *));
*ptr[0] = (char *) malloc(sizeof(char)*5);
strcpy(*ptr[0], "abc");
return;
}
Could someone explain why?
You're passing the parameter ptr by value; the formal parameter ptr in test is a different object from the actual parameter ptr in main, so changing the value of test::ptr is not reflected in main::ptr.
Thus, you need to pass a pointer to ptr into test, and test needs to dereference that pointer to write to the correct object.
For any type T, if you want to modify the value of the function argument, you need to do the following:
void foo( T *param )
{
*param = ...;
}
void bar( )
{
T obj;
foo( &obj );
}
In this particular instance, T is char **.
In C, when you pass an array to a function, the array "decays" to a pointer. The function receives a pointer to the first element of the array. It does not receive the array itself. Any changes made to the pointer assignment in the called function are not reflected in the calling function.
In your first example, test() receives the array of strings, and inside the function, it changes what that pointer points to. So the local copy of ptr, which was NULL, gets allocated memory inside the function, as does ptr[0]. However, those changes are local to test(). They are not reflected in the calling function. When test() finishes executing and returns, the value of ptr in the calling function is still NULL. And you have a memory leak because there is no way to access the memory that was allocated in test().
In order for the changes to be reflected in the calling function, you have to pass a pointer to the array of strings: hence the &ptr in the call and the three-level pointer in the definition of test(). Another, simpler approach would be:
int main()
{
char **ptr= NULL;
ptr = test();
printf("%s", ptr[0]);
return 0;
}
char** test(void)
{
char **ptr = (char **) malloc(sizeof(char *));
ptr[0] = (char *) malloc(sizeof(char) * 5);
strcpy(ptr[0], "abc");
return ptr;
}
One clarification: I said "Any changes made to the pointer assignment in the called function are not reflected in the calling function." This is not the same as saying "Any changes to array elements are not reflected in the calling function." Consider this:
int main (void) {
int array [] = { 0, 1, 2, 3, 4 };
test1 (array);
printf ("%d\n", *array);
test2 (array);
printf ("%d\n", *array);
return 0;
}
void test1 (int* array) {
int new_array[] = { 3, 4, 5, 6, 7 };
array = new_array;
return;
}
void test2 (int* array) {
array [0] = 5; // or *array = 5
array [1] = 6;
array [2] = 7;
array [3] = 8;
array [4] = 9;
return;
}
Output:
0
5
Here in test1() the change is to where the array pointer itself is pointing, which won't be reflected in the caller. So in the calling function, *test is still 0. In test2(), the changes are to the array elements, which are reflected in the caller. Hence the difference in output: *test is now 5. All this uses static rather than dynamic memory allocation, but the principle is the same.
It's because you expect your function not to return a value, but to modify a variable you have already created in another scope.
You expect, from your function, to pass ptr and end up with the following structure:
ptr -> b -> []
where b is a pointer to the array [].
In the first example you are not modifying the outer ptr inside the function, but a copy of it. In that case, to get the desired structure you'd need your function to return a char** so that you could return the allocated pointer. And you wouldn't need to pass the original ptr.
In the second example, on the other hand, you are passing a pointer to the outer ptr, so the function will be modifying the same memory space that the outer ptr uses.
I hope this can help a little.
Consider below code for understandling
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test(char **ptr);
int main()
{
char *ptr= NULL;
test(&ptr);
printf("%s\n", ptr);
return 0;
}
void test(char **ptr)
{
*ptr = malloc(sizeof(char *));
strcpy(*ptr, "abc");
return;
}
Whatever doing in function definition has to be reflect in main function. So if you want to make changes in ptr variable you have to pass the address of the ptr variable.
ptr is single pointer(char ptr) variable, we need to pass address of the pointer(&ptr) variable.
In function definition we are receiving address of pointer variable, so argument has to be the type of double pointer.
This concept is similar to call by reference.
Similar things happening in your code also.
You need to pass address of double pointer to make changes in pointer variable.
Address of double pointer has to taken by triple pointer in function definition.
To expand on the answer from #rcrmn.
It is a good program design to have data get passed "up" the calling structure. In this case main() needs to free the storage it received from test.
Notice that this code avoids all of the double pointers in the original question and still meets the requirements. This is the essence of good programming, write clear, simple, code that gets the job done.
#include <stdio.h>
char *test();
int main()
{
char *ptr = test();
printf("%s", ptr);
free(ptr);
return 0;
}
char *test()
{
char *ptr = (char *) malloc(sizeof(char) * 5);
strncpy(ptr, "abc", 3);
return ptr;
}

Resources