I am still trying to understand about doublepointers.
I do know how double pointers are usually used in most cases like
void foo(char **ptr)
{
// blah
}
int main(void)
{
char *ptr;
foo(&ptr);
}
However i have no idea what one does differently than the other
int main(int argc, char **argv) //Double pointer
int main(int argc, char *argv[]) // Single
When used as a parameter to a function, an array designator [] is exactly the same as a pointer. The two declarations you have for main are in fact identical.
There are times when the two different syntaxes mean different things, but this isn't one of them.
In this case it means you have an array of pointers. Each pointer points to an array of characters. argv[0] is a pointer to the first char* string, argv[1] is a pointer to the second char* string, etc.
I feel your pain! It took me a long time to convince myself that I should treat them exactly the same.
argv[1] points to the first parameter, argv[argc-1] points to the final parameter. Yes, all you sharpshooters, that's true iff argc > 0.
That's my formula and I'm stickin' to it.
Related
I have been messing a bit with C lately and i have come across some "weird" behavior
#include <stdio.h>
int main(int argc, char **argv) {
printf("&argv=%d\n&argv[0]=%d\n", &argv, &(argv[0]));
return 0;
}
the pointer to argv is completely different from the pointer of argv[0]
as C arrays are contiguous shouldn't the pointer to the argv be the same to the start of the first C string?
in my head the argv should look something like this
char **argv = {char *, char *, char *};
where the start of the argv array be the same as the start of the first string
how is this structured and why aren't the two pointers the same?
printf requires that you use the format specifier that matches with the type of the argument that you pass. %d does not match with the type of the arguments that you pass (it requires int or similar), and therefore the behaviour of the program is undefined.
I recommend avoiding printf in general (Edit: question used to be tagged [c++]), but if you must use it, then you can use %p format specifier for void*. You must convert the pointer arguments to void*.
Once you've fixed the program, you'll find that the addresses are indeed different. The explanation is that argv is a pointer that doesn't point to itself. Hence its value is different from where it is stored. It points to another object stored elsewhere.
... the argv array ...
argv is not an array. Function parameters cannot be arrays. argv is a pointer.
You can create an analogous structure like this:
char args[] = "./a.out\0example\0argument";
char* ptrs[] = {
args + 0,
args + 8,
args + 16,
0,
};
int argc = 3;
char** argv = ptrs;
// argv == &ptrs[0]
// argv != &argv
C arrays are contiguous, but on the one hand you took the address of the array, and on the other hand you took the addresses in the array.
This is perhaps more obvious if you print out the argv[i] values for all values of i like this:
$ cat pointer.c
#include <stdio.h>
int main(int argc, char** argv) {
int i;
for (i = 0; i < argc; ++i) {
printf("&argv=%p\targv=%p\t&argv[%d]=%p\n", &argv, argv, i, &(argv[i]));
}
return 0;
}
$ gcc pointer.c
$ ./a.out 1 2 3
&argv=0x7ff7b3716690 argv=0x7ff7b37167e0 &argv[0]=0x7ff7b37167e0
&argv=0x7ff7b3716690 argv=0x7ff7b37167e0 &argv[1]=0x7ff7b37167e8
&argv=0x7ff7b3716690 argv=0x7ff7b37167e0 &argv[2]=0x7ff7b37167f0
&argv=0x7ff7b3716690 argv=0x7ff7b37167e0 &argv[3]=0x7ff7b37167f8
While %p is a better format specifier, your %d would have worked too, if you were printing out the address of the first element of the array (which is just argv) instead of a pointer to the address of the first element of the array (which is &argv and not what you meant).
as C arrays are contiguous shouldn't the pointer to the argv be the same to the start of the first C string?
The address of an array is indeed the same as the address of its 1st element, yes. But argv is not an array, it is a pointer to an array. &argv is the address of the pointer itself, not the address of the array that it is pointing at. Evaluating argv by itself will return the address of the array. And as such, &(argv[0]) is the address of the 1st element of the array.
Try this instead, and you will see that argv and &argv are two different addresses:
printf("&argv=%p\nargv=%p\n&argv[0]=%p\n", &argv, argv, &(argv[0]));
For starters you shall use the conversion specifier %p to output pointers using the function printf.
Function parameters are local variables of the function.
You can imagine the function main the following way
int main( /*int argc, char** argv */) {
int argc = some_argument expression;
char **argv = some_argument_expression;
//...
Thus the expression &argv gives the address of the local variable argv
The expression argv[0] is the first element of the array pointed to by the local variable argv that has the type char **. And the expression &argv[0] gives the address of the first element of the pointed array.
So &argv is the address of the local variable argv that is defined in main as its parameter. While &argv[0] is the address of the first element of an array that is defined outside the function main.
To make it more clear consider a very simple program.
#include <stdio.h>
int main* void )
{
int a[] = { 1, 2, 3, 4, 5 };
int *p = a;
printf( "&p = %p, &p[0] = %p\n", ( void * )&p, ( void * )&p[0] );
}
As you see the expression &p yields the address of the variable p that occupies its own extent of memory while the expression &p[0] yields the address of the first element of the array a that occupies a separate extent of memory.
This question already has answers here:
What should main() return in C and C++?
(19 answers)
Closed 6 years ago.
I have the following function:
int func(int carg, const char **varg) {
//code ...
}
My understanding is the following:
varg is a pointer to a second pointer. This second pointer points to a char. This char is ...
either: a single char (1st case)
or: a char that constitutes the first char of a char array. (2nd case)
Is this understanding correct?
The thing I don't understand is why you would want to pass a pointer to a pointer as an argument.
If you wanted to pass (by reference) a single char to the function, you could simply write:
int func(int carg, const char *v) {
//code ...
}
In the 2nd case, where you want to pass (by reference) a char array to the function, one could use the same function (where this time, v points to the first element of the array passed to the function):
int func(int carg, const char *v) {
//code ...
}
In summary, I don't understand why you would want to use a pointer to a pointer as argument to a function.
The concrete case I have is the following declaration of a main function:
int main(int carg, const char **varg);
**varg handles the arguments on the command line.
One can access the command line arguments using varg[1], varg[2], etc.
So, obviously, what **varg does is simply to save the command line arguments in an array. But this could be achieved in a more simple way with the following code:
int main(int carg, const char *varg);
What am I missing?
To store a string you need an array of chars in memory. Pointer to any array in C is [type of array elements] * which is essentially pointer to first element in this array. In case of strings it is char *.
Arguments of command line is array of strings. That means, you have an array, where each element is cell in memory, containing pointer to another array - array of char. In this case type of elements in this array of pointers to array is char *, what give us proper type of pointer to this array (just substitute char * to formula above): char **.
I just found a little confusion while using increment operator in pointer array.
Code 1:
int main(void) {
char *array[] = {"howdy", "mani"};
printf("%s", *(++array));
return 0;
}
While compiling, gcc throws a well known error "lvalue required as increment operand".
But, when I compile the below code it shows no error!!! Why?
Code2:
int main(int argc, char *argv[]) {
printf("%s",*(++argv));
return 0;
}
In both cases, I have been incrementing an array of pointer. So, it should be done by this way.
char *array[] = {"howdy","mani"};
char **pointer = array;
printf("%s",*(++pointer));
But, why code2 shows no error?
Arrays cannot be incremented.
In your first code sample you try to increment an array. In the second code sample you try to increment a pointer.
What's tripping you up is that when an array declarator appears in a function parameter list, it actually gets adjusted to be a pointer declarator. (This is different to array-pointer decay). In the second snippet, char *argv[] actually means char **argv.
See this thread for a similar discussion.
This question already has answers here:
C difference between *[] and **
(8 answers)
Closed 2 years ago.
CODE 1
#include<stdio.h>
int main(int argc, char *argv[])
{
int j;
printf("%d", argv[1][0]);
return 0;
}
CODE 2
#include<stdio.h>
int main(int argc, char **argv)
{
int j;
printf("%d", argv[1][0]);
return 0;
}
CODE 1 and CODE 2 both give same output. but argument 2 of main function in CODE 1 and CODE 2 are different. Array of pointers are created above data section at compile time. argv is array of pointers. Then we should declare argument in main function as pointer to pointer to character i.e., **argv. How it is correct to declare as in CODE 1?
It is fundamental to c that char** x and char* x[] are two ways of expressing the same thing. Both declare that the parameter receives a pointer to an array of pointers. Recall that you can always write:
char *parray[100];
char **x;
x = &parray[0];
and then use x identically.
Basically, char* argv[] means array of char pointers, whereas char** argv means pointer to a char pointer.
In any array, the name of the array is a pointer to first element of the array, that is, it contains the address of the first element.
So in the code given below, in char array x, x is a pointer to first element, '1', which is a character. So it's pointer to a character.
And in array arr, arr is pointer first element, x, which is itself a pointer to a character. So it a pointer to another pointer.
Hence, x is char*, and arr is char**.
While receiving something in a function, basic rule is that, you have to tell the type of the thing you are receiving. So either you simply say that you want to receive a char**, or you can also say char* arr[].
In first case, we don't need to think anything complex. We simply know, we are receiving an array of char*. Don't we know this? So, we receive it, and use it.
In second case, it is simple, as i have explained above that arr is a char**, you can put this as it's type and receive it safely. Now the system knows the type of the stuff we have received, we can access next elements by simply using array annotation. It's like, we have received the starting address of the array, we can surely go to the next elements, and as we know it's type, we know what it contains and how we can use that further. We know it contains pointer to char, so we can legally access them as well.
void func1(char* arr[])
{
//function body
}
void func2(char** arr)
{
//function body
}
int main()
{
//x, y and z are pointer to char
char x[3]={'1', '2', '3'};
char y[3]={'4', '5', '6'};
char z[3]={'7', '8', '9'};
//arr is pointer to char pointer
char* arr[3]={x, y, z};
func1(arr);
func2(arr);
}
They're exactly the same. §5.1.2.2.2 of the C11 standard states:
The function called at program startup is named main. The
implementation declares no prototype for this function. It shall be
defined with a return type of int and with no parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though
any names may be used, as they are local to the function in which they
are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent;10) or in some other implementation-defined
manner.
10) Thus, int can be replaced by a typedef name defined as int, or
the type of argv can be written as char ** argv, and so on.
Clearly the intent is for both declarations to be identical. On top of that, the rule is described in §6.7.6.3/7:
A declaration of a parameter as ‘‘array of type’’ shall be adjusted
to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. ...
[EDIT] Using GCC at the time of the comment probably GCC 7.2
declaring an array like this
char array[]
makes it const which means that you CAN'T have the following code
char array[] = "hello";
array = "hey";
even though the second string is smaller and should fit you get this error
error: array type 'char [6]' is not assignable
if you have **argv you can write
main(int argc, char **argv)
{
char **other_array;
/*
* do stuff with other_array
*/
argv = other_array;
}
if you have *argv[] then
main(int argc, char *argv[])
{
char **other_array;
/*
* do stuff with other_array
*/
argv = other_array;
}
gives you this warning
warning: assigning to 'const char **' from 'char **' discards qualifiers in nested pointer types
so it is technically a small optimisation as if you had written const
I learning to use Pointers.
I have a few questions about an exercise code I wrote.
First, if I have the following function code:
//function prototype
void processCars(char *, char []);
int main(){
...
//actual callto the function
processCars(strModel[x], answer);
...
}
void processCars(char * string1, char string2[])
{
...
}
How would it be correct the define the arguments of this processCars function?
The first one - char * - is a pointer to char, which is the start location of the string (or better an array of chars) ?
The second is actually an array of chars directly.
Now, supposed I want to pass by reference a few array of strings and even array of structs. I managed to create the following code which works, but I still don't fully get what I'm doing.
typedef struct car {
char make[10];
char model[10];
int year;
int miles;
} aCar; // end type
// function prototype
void processCars( aCar * , char **, char **, int *, int *);
//aCar * - a pointer to struct of type car
//char **, char **
// int * - a pointer to integer
// Arrays passed as arguments are passed by reference.
// so this prototype works to
//void processCars( aCar * , char **, char **, int [], int []);
int main(){
aCar myCars[3]; // an array of 3 cars
char *strMakes[3]={"VW","Porsche","Audi"}; // array of 3 pointers?
char *strModel[3]={"Golf GTI","Carrera","TT"};
int intYears[3]={2009,2008,2010};
int intMilage[3]={8889,24367,5982};
// processCars(myCars, strMakes);
processCars(myCars, strMakes, strModel, intYears, intMilage);
return 0;
} // end main
// char ** strMakes is a pointer to array of pointers ?
void processCars( aCar * myCars, char ** strMakes, \
char ** strModel, int * intYears, \
int * intMilage ){
}
So, my qeustion is how to define this "char ** strMakes". What is it, why is it working for me?
I have also noticed, I can't change part of the string, because if I correct (or the references I read)
strings are read only. So, like in python, I can use array indices to access the letter V:
printf("\n%c",strMakes[0][0]);
But, unlike in python, I can't change it:
strMakes[0][0]="G" // will not work? or is there a way I could not think of?
So, thanks for reading through my long post and many question about pointers and c strings. Your answers are appreciated.
Within the function itself, both arguments will be pointers. The [] in the parameter list makes absolutely no difference, it's just syntactic sugar.
Although there is a distinct difference between an array and a pointer, a passed array to a function always decays to a pointer of the corresponding type. For example, an array of type char[3] would decay to char *, char *[3] would decay to char **.
char *strMakes[3] is an array of length 3 that holds pointers to strings stored somewhere else, probably in a read-only area of the process. An attempt to modify the strings themselves will result in undefined behaviour, most probably a protection fault.
If you want to be able to modify the strings, you could declare it as an array holding arrays, not pointers:
char strMakes[3][20] = {"VW", "Porsche", "Audi"};
This way the strings will be stored consecutively within the bounds of the outer array.
Another way is to still have an array of pointers, but the pointers should point to mutable memory:
/* these strings are mutable as long as you don't write past their end */
char str1[] = "VW";
char str2[] = "Porsche";
char str3[] = "Audi";
char *strMakes[3] = {str1, str2, str3};