What is the difference between char **ptr and char *ptr[] in C? - c

#include<stdio.h>
void display(int n, char *str[])
{
int i=0;
while(i<n) printf("%s ",str[i++]);
}
int main()
{
display(1,"Hello");return 0;
}
when I run this above code I get warnings as
arr.c: In function 'main':
arr.c:11:12: warning: passing argument 2 of 'display' from incompatible pointer
type
display(1,"hello");
^
arr.c:3:6: note: expected 'char **' but argument is of type 'char *'
void display(int n,char *str[])
But then how is it different from
int main(int argc, char * argv[])
And what is the difference between
char **argv and char *argv[]
I am strictly not asking about something like char *argv[100]

As a parameter of a function both char **ptr and char *ptr[] are equivalent, otherwise they are different. Former is a pointer to pointer to a char while latter is an array of pointers to char.
When a string literal is passed to a function, then pointer to its first character (char * type) is passed. You need to change the function's second parameter to char *str.
void display(int n, char *str)
{
// Function body
}

Well, char **ptr is a double pointer (pointer to a pointer) of char while char *ptr[] is an open array of pointer to char.
According to cdel, char **p; gives the result of "declare p as pointer to pointer to char" while char *p[]; gives "declare p as array of pointer to char."
Character strings are always arrays, and arrays are generally always pointers, so the two are generally equivalent which means that **ptr = *ptr[]. What you end up with is an array of an array of chars, or an array of strings. Take main() for instance:
int main(int argc, char **argv)
{
int i;
for (i = 0; i < argc; i++)
{
if (strcmp(argv[i], "some string") == 0) do something;
}
Do some stuff;
return(0);
}
Another way to declare it is
int main(int argc, char *argv[])
Programmatically, it's easier to understand *ptr[] than **ptr.

Related

Difference of char **a and char *a[]

I am new to programming and C in general and the last few weeks I try to get the concept of pointers, arrays and how they are connected.
At the moment I experiment with command line arguments in C and I read here on this platform that argv can be syntactically defined differently, however the semantic stays the same.
int main(int argc, char *argv[])
is equal to
int main(int argc, char **argv)
Okay, but why is my code behaving differently when I try to initialize an array in these ways:
char *s[] = {"hallo", "12345"};
printf("%c und %c", s[0][4], s[1][2]);
I get as output as expected: o and 3.
But when I initialize the array like
char **s = {"hallo", "12345"};
printf("%c und %c", s[0][4], s[1][2]);
I get a segmentation fault or other errors which I cannot understand like (near initialization for ‘s’)
I guess you cannot initialize an pointer to a pointer array with 2 asterisks.
Maybe someone can provide me with more information about these relation and how these 2 definitions differ from each other.
They are completely different:
char *s[]
is an array of pointers. Arrays cannot be assigned or used as values
This code will not compile:
char *a[] = {"hallo", "12345"};
char *a1[2];
char **s = (char *[]){"hallo", "12345"};
char **s1;
void foo(void)
{
a++;
}
void bar(void)
{
a1 = a;
}
char **s
is a pointer to a pointer and can be assigned or used as an lvalue.
This code will compile:
char *a[] = {"hallo", "12345"};
char *a1[2];
char **s = (char *[]){"hallo", "12345"};
char **s1;
void foo(void)
{
s++;
}
void bar(void)
{
s1 = s;
}
https://godbolt.org/z/vqxv913WY

What is the meaning of changing char pointer to int pointer

I have the following code from previous exam in c:
int main(int argc, char **argv) {
char s[] = "123";
int* a = (int*) s;
printf(("%x"),*a);
return 0;
}
The output is: 333231
My question is why? how does changing the pointer effect it?
You don't have to declare a separate variable. This would do:
printf(("%x"),(int*)s);
The pointer type dictates how the pointee is interpreted when the pointer is dereferenced.

Pointer to function Prototype

i am trying to figure out what those prototypes mean
1.int* (*fpData)(int (*paIndex)[3] , int (* fpMsg) (const char *),
int (*fpCalculation[3]) (const char *));
2.int* (*fpData[2])(int (*paIndex)[3] , int (* fpMsg) (const char *),
int (* fpCalculation[3]) (const char *));
3.int* (*(*fpData)(const char *))(int (*paIndex)[3] ,
int (* fpMsg) (const char *),
int (* fpCalculation[3]) (const char *));
First you should find actual variable which is being declared. In all 3 examples this is fpData. Then you should start to read declaration staring from this variable moving from inside to outside.
So, let us begin with first example. We see fpData, so we say "fpData is...", then we see "*" before "fpData", so we say "fpData is pointer to...", then we see function type declaration outside of *fpData, so we say "fpData is pointer to function...". Then we should read types of arguments and result of this function.
Well, you can read types for all 3 arguments without problems. They are:
"paIndex is pointer to array of length 3 of ints"
"fpMsg is pointer to function from const char * to int"
"fpCalculation is array of length 3 of pointers to function from const char * to int"
In the last argument you should note that [3] has the higher priority than "*". I mean that while reading declaration from inside to outside you should read first array and then pointer. I. e. int *a[3] is "a is array of length 3 of pointers of int" and not "pointer to array".
Assuming all this I think you can read 2nd declaration without problems.
Now you should learn this: type of function result is written outside (i. e. BEFORE AND AFTER) of everything else.
Let us consider this:
char (*(*fp)(int))(double)
What this means? Well let's start reading, "fp is pointer to function which takes int and returns... what?" Well, we already have read (*fp)(int) part. Now we want to read everything else. And we want to understand what is result type of function we already read. And now we should note that result of function is the thing which is written OUTSIDE (i. e. BEFORE and AFTER) of everything else, i. e. outside of what we already read.
So, we have read (*fp)(int). Everything else, i. e. char (*XXX)(double) is return type for function we already read. So, well, let's continue reading. Finally we will get this:
"fp is pointer to function which gets int and returns pointer to function which gets double and returns char".
Now you can read 3rd declaration without problems
The C gibberish ↔ English link that chux posted still looks like gibberish to
me. So I'll try to sound more human:
int* (*fpData)(int (*paIndex)[3] , int (* fpMsg) (const char *),
int (*fpCalculation[3]) (const char *));
This declares a function pointer fpData that returns a pointer to int. The
function takes 3 variables of the following types:
paIndex is a pointer to an int array of dimension 3. This can be used for
example when you have this:
void bar(int (*paIndex)[3])
{
}
void foo(void)
{
int fields[5][3] = { {1,1,1}, ... };
bar(fields);
}
fpMsg is a function pointer that returns an int. The function takes one
arguments only, a const char* (a string basically).
fpCalculation is an array of dimension 3 of function pointers that return
int. The functions take on argument only: a const char*.
This is a beast of a function pointer, it works in an evironment like this:
#include <stdio.h>
int msg(const char *name)
{
printf("msg: %s\n", name);
return 0;
}
int abc1(const char *name)
{
printf("abc1: %s\n", name);
return 0;
}
int abc2(const char *name)
{
printf("abc2: %s\n", name);
return 0;
}
int *scary_function(int (*paIndex)[3] , int (* fpMsg) (const char *),
int (*fpCalculation[3]) (const char *))
{
fpMsg("fpMsg");
fpCalculation[0]("fpCalculation0");
fpCalculation[1]("fpCalculation1");
fpCalculation[2]("fpCalculation2");
for(int i = 0; i < 4; ++i)
{
for(int j = 0; j < 3; ++j)
{
printf("%-3d ", paIndex[i][j]);
}
puts("");
}
return NULL;
}
void foo(void)
{
int matrix[4][3] = { {1,2,3}, {4,5,6}, {7,8,9}, {10,11,12} };
int (*fpcalcs[3])(const char*) = { msg, abc1, abc2 };
int* (*fpData)(int (*paIndex)[3] , int (* fpMsg) (const char *),
int (*fpCalculation[3]) (const char *));
fpData = scary_function;
// calling the function through the function pointer
fpData(matrix, msg, fpcalcs);
}
int main(void)
{
foo();
return 0;
}
The output of this is
msg: fpMsg
msg: fpCalculation0
abc1: fpCalculation1
abc2: fpCalculation2
1 2 3
4 5 6
7 8 9
10 11 12
So I've explained in detail how to parse the declaration of these function
pointers. Now try understanding the other 2 yourself, if you still have problems,
post a comment.
1.int* (*fpData)(int (*paIndex)[3] , int (* fpMsg) (const char *), int (*fpCalculation[3]) (const char *));
Here, fpdata is pointer to a function which takes three arguments and returns a pointer to an integer. The arguments are as follows:
pointer to 3 elements integer array,
pointer to a function which takes const char pointer as an argument and return type int,
array of 3 function pointers and each function takes const char pointer as an argument and return type is int
2.int* (*fpData[2])(int (*paIndex)[3] , int (* fpMsg) (const char *), int (* fpCalculation[3]) (const char *));
In this case, fpdata is array of 2 function pointers, and each function takes three arguments -
pointer to 3 elements integer array,
pointer to a function which takes const char pointer as an argument and return type int,
array of 3 function pointers and each function takes const char pointer as an argument and return type is int
The return type is a pointer to an integer
3.int* (*(*fpData)(const char *))(int (*paIndex)[3] , int (* fpMsg) (const char *), int (* fpCalculation[3]) (const char *));
Finally, fpdata is a pointer to a function which takes three arguments -
pointer to 3 elements integer array,
pointer to a function which takes const char pointer as an argument and return type int,
array of 3 function pointers and each function takes const char pointer as an argument and return type is int
The return type is a function pointer which takes const char pointer as argument and return type is pointer to an integer.
int* (*fpData)(int (*paIndex)[3] , int (* fpMsg) (const char *),
int (*fpCalculation[3]) (const char *));
it is function prototype declaration.
Where fpData is a function name, function that takes three arguments:
int (*paIndex)[3]
int (* fpMsg) (const char *)
int (*fpCalculation[3]) (const char *)
…and returns a function pointer [pointer to a function that take no argument but returns pointer to an integer].
Details :: Given function can be written as below
typedef int* (*ret_func_ptr) ();
ret_func_ptr (*fpData)(int (*paIndex)[3] , int (* fpMsg) (const char *),
int (*fpCalculation[3]) (const char *));

C Array to Pointers

Please explain why the below code fails at line 10.
How can I print values of p, i.e. Hello World.
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
char ar[200] = "Hello World";
strcat(ar, " !");
printf("%s\n", ar);
char **p = &ar;
printf("%s\n", *p[0]);
return 0;
}
EDIT:
Just to clarify more on what I want to achieve. I have a function that accepts char** as argument, hence why I want to convert char ar[200] into char**, but the application freezes.
You have declared a character array and assigned value to it. If you just mention the name of the array, you are actually mentioning the base address of this array. Pointers can store address, you can define a char pointer and assign the base address of your character array to it.
for example
char ar[200]="Hello World";
char *p=a; //assign the base address of a to p;
You can then print the string using the %s format specifier with the base address of your character array(string).
printf("%s",a);// print the string "Hello World". here a is the base address
printf("%s",p);//print the string "Hello World". here p is the base address
This will work
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
char ar[200] = "Hello World";
strcat(ar, " !");
printf("%s\n", ar);
char *p = ar;
printf("%s\n", p);
return 0;
}
Edited for your convenience
char *q=a;
char **P=&q;
printf("%s",*p);
if this is what you want
Arrays already "decay" to the address of their first element in most contexts. This behavior differs from other variables, even from the other aggregates, structs. The reasons are rooted deep in the history of C (namely, no joke, in B1).
One of the contexts though where an array does not decay is when its address is taken: the address operator yields a pointer to array, not a pointer to pointer to char:
char arr[6] = "abcde"; // 5 letters plus '\0'
char (*parr)[6] = &arr; // pointer to array of 6 elements
Curiously enough, dereferencing this pointer twice yields the first char in the array, as if parr were a pointer to pointer to char. The reason is that *parr simply is the original array, and dereferencing that is quite normally its first element. This is likely the source of much confusion:
printf("%c", **parr);
Traditionally (i.e. in the 1970s) pointer was pointer, and their types didn't matter much. (There is a big difference though: What value does parr+1 have?) But it's nice to compile without warnings and to understand what one is doing. So how do we get your requirement, a pointer to a pointer to a char, for printing arr? The answer is, just use a pointer to a pointer!
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
char ar[200] = "Hello World";
strcat(ar, " !");
printf("%s\n", ar);
char *p = ar; // pointer to char:
// array "decays" to address of first char
char **pp = &p; // pp is a pointer to a pointer to char.
// The point is, it points to the "pointer to char" p.
printf("%s\n", *pp); // *pp is what pp points to:
// p, a simple pointer to char. That's what "%s"
// expects. p is initialized and points to
// the first char in ar.
return 0;
}
1Cf. the interesting paper by Dennis Ritchie, "The Development of the C Language", p.7
gcc main.c -o main
main.c: In function ‘main’:
main.c:9:16: warning: initialization from incompatible pointer type [enabled by default]
char **p = &ar;
^
main.c:10:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
printf("%s\n", *p[0]);
^
expects argument of type ‘char *’, but argument 2 has type ‘int’ seems very clear :P
You can print your string by changing you program by
int main(int argc, char **argv) {
char ar[200] = "Hello World";
strcat(ar, " !");
char *p = ar;
printf("%s\n", p);
return 0;
}
In c ar is equal to &ar, because arrays are basically memory addresses to their first elements.
So you only need a pointer to a char not a pointer to a pointer to a char.
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
char ar[200] = "Hello World";
strcat(ar, " !");
printf("%s\n", ar);
char *p = &ar;
printf("%s\n", p);
return 0;
}
This question is an interesting example of the difference between arrays and pointers. It is common to think of arrays as pointers, but that isn't quite true. The fact that char ar[200] doesn't make ar into a char pointer is why you can't use a char** to point to ar. On the other hand, arrays decay to pointers in function calls, so the following code does work (though it is terribly unmotivated):
#include <stdio.h>
#include <string.h>
void printString(char ar[]){
char **p = &ar; // as in original code
printf("%s\n",*p);
}
int main(int argc, char **argv) {
char ar[200] = "Hello World";
strcat(ar, " !");
printf("%s\n", ar);
printString(ar);
return 0;
}
How can I print values of p, i.e. Hello World.
You do not need a pointer to pointer for this purpose. A simple pointer will do.
char *p;
p = ar;
printf ("%s\n",p);
Example of when to use **pointers
#include <stdio.h>
void foo(char **bar)
{
*bar = "some text";
}
int main(int argc, char *argv[])
{
char *temp;
foo (&temp);
printf ("temp=%s\n", temp);
return 0;
}
I explain in the comments of your code.
EDIT: Do not copy following code
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
char ar[200] = "Hello World";// technically an array is a pointer, so char *ar and char[] are the same
strcat(ar, " !");// pass the pointer to treat strings
printf("%s\n", ar);// pass the pointer to treat strings
char **p;// here is the problem you were giving the address of your pointer to a pointer of pointer in inline wich makes more confusing
(*p) = &ar; // here is the correct assingment
printf("%s\n", *p);// so here you should pass *p
return 0;
}
EDIT: This solution is far safer in real life situations
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
char ar[200] = "Hello World";// technically an array is a pointer, so char *ar and char[] are the same
strcat(ar, " !");// pass the pointer to treat strings
printf("%s\n", ar);// pass the pointer to treat strings
// This solution initializing is better because it avoids editing other variables
char *p = ar;
char **pp = &p;
printf("%s\n", *pp);// so here you should pass *pp
return 0;
}

Passing char * vs char ** as parameters to a function in C

I've read several discussions of passing char * in C.
stackoverflow: passing-an-array-of-strings-as-parameter-to-a-function-in-c
stackoverflow: how-does-an-array-of-pointers-to-pointers-work
stackoverflow: whats-your-favorite-programmer-ignorance-pet-peeve
drexel.edu: Character arrays
Many of them include discussions of arrays, but I want to stay away from that.
I'm writing a sample program to teach myself about the passing of char * and char ** in C. This is an exercise in passing char *, without using (pointers to) arrays. Also no concerns for execution efficiency. :-)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void get_args_works(int, char **, char **);
void get_args_broken(int, char **, char *);
char *get_string(int, char **);
int main(int argc, char **argv)
{
char *string_works;
char *string_broken;
get_args_works(argc, argv, &string_works);
get_args_broken(argc, argv, string_broken);
printf("in main string_works (%p) = %s\n",string_works,string_works);
free(string_works);
printf("in main string_broken (%p) = %s\n",string_broken,string_broken);
free(string_broken);
}
void get_args_works(int argc, char **argv, char **string)
{
*string = get_string(argc, argv);
printf("in get_args_works %p string %s\n",*string,*string);
}
void get_args_broken(int argc, char **argv, char *string)
{
string = get_string(argc, argv);
printf("in get_args_broken %p string %s\n",string,string);
}
char * get_string(int argc, char **argv)
{
int i;
char *string;
string = malloc(40);
// placeholder in case -s switch not found below
strcpy(string,"-s switch not found below");
for(i = 0; i < argc; i++)
{
if(argv[i][0] == '-')
{
switch(argv[i][1])
{
case 's':
// release above malloc(40) for "-s switch not found below"
free(string);
// make room for storing variable
string = malloc(strlen(argv[++i]) + 1);
// the argv just after -s
strcpy (string,argv[i]);
break;
}
}
}
return string;
}
You can also view the same code on github
The above code is somewhat self documenting. main() declares two char * variables, and passes them as parameters to their respective get_args() functions.
Each get_args() function calls char * get_string(int, char **), using the exact same call (but different way to collect the return value).
get_string() works fine; it does a malloc() and returns the pointer back to the calling function. That code works, and each get_args() function receives the return value as I expect.
But then, when the get_args() functions return to main(), why does the dereferenced pointer value get back to main (from get_args_works(), but not the pointer's value (from get_args_broken())?
(i.e. I can see that if I dereference the pointer (&string_works) when sending as a parameter, it works. But why? Isn't char * string_broken already a pointer? Why does it need the "extra" dereference when sending as a parameter?)
I'm hoping for a winning answer that explains how you (yes, you) conceptualize sending char * as a parameter vs receiving it as the function's return value.
int get_args_broken(int argc, char **argv, char *string)
{
string = get_string(argc, argv);
printf("in get_args_broken %p string %s\n",string,string);
}
You're only modifying the string local (automatic) variable. That's not visible to the caller in any way. Note that this means you're freeing a wild pointer in main.
It's wrong for the same reason:
int get_sum(int sum, int a, int b)
{
sum = a + b;
}
is; the parameter is copied by value. Also, you're not returning an int (as you declared you would).
int get_args_works(int argc, char **argv, char **string)
{
*string = get_string(argc, argv);
printf("in get_args_works %p string %s\n",*string,*string);
}
is correct (except the missing return). You're not modifying string, which would be pointless. You're modifying the object at the location in string, which in this case is a char *.
EDIT: You would need to triple * the argv if there was a function calling main, and you wanted to set that function's variable to a different char **. E.G.
void trip_main(int *argc, char ***argv)
{
*argc = 10;
*argv = malloc(*argc * sizeof(char *));
}
void caller()
{
char **argv;
int argc;
trip_main(&argc, &argv);
}
One of the needs to use Pointer to a pointer (here get_args_works()) is to modify (or return) more than on variable from a function, as in C it's not possible to return more than one variable.
get_args_works() works 'coz, you are passing pointer to a pointer & a reference to it is there in your main().
But in get_args_broken() you are passing just a pointer. Nothing wrong here, now you do malloc() & return back the memory allocated string to get_args_broken(), still nothing wrong here. But now, this mem allocated string is local & main() does not have a reference to this var. So when you dereference char *string_broken; in main() it might cause undefined behavior.
Hope this's clear.

Resources