I am trying to create argv for a new process(trying to use execvp), and I checked the execvp manual page which says it needs char *const argv[].
I assume this is an pointer to array of char pointers. So is it possible to pass double pointer of char to this argument?
Basically, what I am trying to do is as following
(argvcounter is number of arguments. ex) cat a -> argvcount = 2)
int argvcount;
char **argv;
...
argv = malloc(sizeof(char*)*(argvcount+1));
for (int i = 0; i<argvcount; i++){
argv[i] = some char pointer;
}
argv[-1] = NULL;
I am not sure about the last line either. I am setting last element to NULL since the last element of array of arguments have to be NULL.
Is it possible to pass this argv to execvp?
Thank you.
According to the C Standard (5.1.2.2.1 Program startup, p.#2)
— argv[argc] shall be a null pointer
So you have to write
argv[argvcount] = NULL;
This statement
argv[-1] = NULL;
does not make sense and results in undefined behavior.
I assume this is an pointer to array of char pointers. So is it
possible to pass double pointer of char to this argument?
An array designater with rare exceptions is implicitly converted to pointer to its first element.
So if for example you have an array like this
char * argv[argvcount];
then passed to a function it is converted to pointer to its first element and has type char **.
On the other hand, these function declarations
void f( char *a[] );
and
void f( char **a );
are equivalent because the compiler adjusts the type of a parameter declared as an arrray to the type of pointer to an object of the array element type.
it needs char *const argv[]. I assume this is an pointer to array of char pointers.
No, it is an array of char* const pointers. It might help reading these declarations from right to left:
[] An array (of unknown size)...
argv ...named argv...
const ... of const...
* ...pointers...
char ...to char.
In plain English: An array (of unknown size) named argv, of read-only pointers to character.
So is it possible to pass double pointer of char to this argument?
Please note the subtle difference between arguments and parameters. Parameter referring to the variable in the function declaration, argument referring to the things you pass to the function on the caller side. It matters here.
Because a function taking a parameter of type char *const argv[], will have that parameter silently "adjusted" by the compiler into a pointer to the first element (sometimes called "array decay"). This is why we don't have to specify the array size - it will "decay" no matter the array size.
The first element is a char*const and a pointer to such an element is of type char*const*, so that's the type that the function will expect. A pointer to a const pointer to char - at the second level of indirection, the pointer itself cannot be modified.
As it happens, char** is a type that may be implicitly converted to char*const*, because the latter is a "qualified" version of the former - it is the same type but with "more const in the right places". Generally, any type* can be converted to type*const.
Had the parameter been const char* argv[], it wouldn't have been possible to use char**, because in that case the const belongs to the pointed-at type and not the pointer.
As already pointed out, note that argv[-1] = NULL; is nonsense, it should be argv[argvcount] = NULL;
Related
I know this is a beginner question, but I can not understand how it works, on every source I find I see a different way to do the same, and I don't understand the difference between these ways to build a function in c which returns a string.
What is happening when:
I write the asterisk after the return type?
char* my_function(){...}
What if write the asterisk before function name?
char *my_function(){...}
What is the asterisk between both?
char * my_function(){...}
What 2 asterisk means?
char **my_function(){...}
And yes, the next code compiles:
char* * **my_function(){...}
OR... are they all the same thing?
char* my_function(){...} defines a function returning pointer to char.
char *my_function(){...} defines a function returning pointer to char. Same as above - different style.
char * my_function(){...} defines a function returning pointer to char. Same as above - different style.
What 2 asterisk means? --> a pointer to a pointer.
char **my_function(){...} defines a function returning pointer to pointer to char. Not the same as above - different return type.
char* * **my_function()(){...} defines a function returning pointer to pointer to pointer to pointer to char. Not the same as above - different return type.
So long as the asterisks lie between char and my_function, the spacing doesn't make any difference.
In all cases they form part of the return type of the function.
char* means the return type is a pointer to a char.
char** means the return type is a pointer to a pointer to a char.
And so on.
In a declaration, T *p, T* p, and T * p are all parsed as T (*p) - the * is part of the declarator, not the type specifier. So the first three function declarations all declare my_function to return a pointer to char.
T **p declares p as a pointer to a pointer to T. Yes, multiple indirection is possible, and you can have pointers to pointers, pointers to pointers to pointers, etc.
Basic rules:
T *p; // p is a pointer to T
T *p[N]; // p is an array of pointer to T
T (*p)[N]; // p is a pointer to an array of T
T *f(); // f is a function returning a pointer to T
T (*f)(); // f is a pointer to a function returning T
T const *p; // p points to a const T
const T *p; // same as above
T * const p; // p is a const pointer to T
The asterisk denotes pointers, they're one of the most important concepts to have a grasp on if you want to be programming in C.
char* is a pointer to a char, char** is a pointer to a char*.
The spacing is irrelevant.
I suggest you take a more in-depth look at pointers, what they are and how to use them.
Isn't the address of an array and thus of all its elements as well constant anyway?
And if so, in a declaration like:
char *const argv[]
isn't the const qualifier redundant?
No, the const in char *const argv[] is not redundant.
First, const and "constant" are actually two different things in C, even though the const keyword is obviously derived from the word "constant". A constant expression is one that can be evaluated at compile time. const really means "read-only". For example:
const int r = rand();
is perfectly legal.
Yes, the address of an array -- like the address of any object -- is read-only. But that doesn't mean that the value of the array (which consists of the values of its elements) is read-only, any more than any other object is necessarily read-only.
Consider these three declarations:
char *arr1[10];
char *const arr2[10];
const char *arr3[10];
arr1 is a 10-element array of pointers to char. You can modify the char* elements and you can modify the objects that those elements point to.
arr2 is an array of const (read-only) pointers to char. That means that you can't modify the char* elements of the array (once they're initialized) -- but you can still modify the char objects or arrays that those elements point to.
And arr3 is an array of pointers to const char; you can modify the array elements, but you can't modify what they point to.
Now the fact that you used the name argv suggests that you're talking about the second parameter to main, which has some huge effects on this. The language specifies that main's second parameter is
char *argv[]
or, equivalently,
char **argv
There is no const. You can probably get away with adding one, but it's best to follow the form specified by the standard. (Update: I see from your comment that you're asking about the argv parameter of getopt(), which is defined as char * const argv[].)
And since it's a parameter defined as an array, another rule comes into play: a parameter defined as an array of some type is "adjusted" to a pointer to that type. (This rule applies only to parameters.) This isn't a run-time conversion. A function cannot have a parameter of array type.
The relationship between arrays and pointers in C can be confusing -- and there's a lot of misinformation out there. The most important thing to remember is that arrays are not pointers.
Section 6 of the comp.lang.c FAQ is an excellent explanation of the details.
Isn't the address of an array and thus of all its elements as well
constant anyway?
Yes, and it is true for any object in C. Recall that by object here, we mean a location in memory having a value and referenced by an identifier. The identifier is bound to a fixed memory location throughout its scope and you cannot change it. You can change the value of the object though.
int a = 4;
a = 6; // legal. you can change the value of the object
&a = 23456; // illegal. you cannot change the address of the object
Similarly, an array is also an object and each of its elements will have a fixed memory address. However, the value held by an element of the array has nothing to do with the address of the element.
Note that if the declaration appears in a function parameter list, then the following are equivalent
char *const argv[]
char *const *argv
which means that argv is a pointer to an object which is of type char *const, i.e., a constant pointer to a character. It's obvious that char *const *argv and char **argv are different. So let's take another example.
char *const argv[10];
The above statement defines argv to be an array of 10 constant pointers to a character. This means that you have to initialize the array and cannot later change the pointers to point to a different character. However, this has nothing to do with the address of the array elements.
char c = 'A';
char d = 'B';
char *const argv[2] = {&c, &d};
argv = &c; // illegal. you cannot the change the address of an object
argv[0] = &d; // illegal. you cannot change the value of the array element
*argv[0] = 'C'; // legal. you change the value pointed to by the element
Without the const qualifier, char *argv[2] means an array of 2 pointers to characters.
This is clearly different from the case when we have the const qualifier as explained above. Therefore, to answer your second question, no, the const qualifier is not redundant. That's because the const qualifier qualifies the type of the array elements.
No, it isn't. char *const argv[] is an array of constant pointers to char. So the const makes the pointers in the array constant (you cannot change them to point to other strings in memory).
Basically my code crashes in NucleoProf_init, judging by gdb's stack-trace, and by the fact that is the only function that I call.
#include <HsFFI.h>
static char *argv[] = {"NucleoProf", "", "", 0};
static int argc = 1;
HsBool NucleoProf_init(void){
// Initialize Haskell runtime
hs_init(&argc, (char***)&argv );
return HS_BOOL_TRUE;
}
I suspect that it is the way I pass the argv argument, or perhaps, the typecast of argv, because the stack-trace contains the following:
#3 0x00007ffff5956282 in setFullProgArgv ()
from /usr/lib/ghc/libHSrts-ghc7.4.1.so
#4 0x00007ffff5956d04 in hs_init_ghc () from /usr/lib/ghc/libHSrts-ghc7.4.1.so
#5 0x00007ffff5b9ed4f in NucleoProf_init ()
Question: Is this the correct way of "synthesizing" a trivial command line?
You can try this:
char ** p = argv;
hs_init(&argc, &p);
It's unclear why you would need to pass the array by address, but I don't know the API you're using. Double-check the manual to see if those values can be changed by the function and if you need to process them afterwards.
It's wrong because, firstly, it's the wrong type. Taking the address of an array results in a pointer to an array. &argv has type char *(*)[4], i.e. "a pointer to an array of 4 pointers to char". This is not the char *** type that you want. You are forcibly casting it to hide the type incompatibility.
You want a char ***, which is a pointer to an actual char ** variable. But you do not have a char ** variable anywhere. You have argv, a char *[4] variable, which is completely different. An array variable is just that -- a collection of its elements in sequence in memory; there is no address of anything stored anywhere in memory.
Your fundamental confusion might be the fact that arrays are not pointers. Arrays have different sizes (the size of an array is its length times size of its component type), pointer and array types (pointer to an array is very different from from a pointer to a pointer; same with array of arrays and array of pointers), and semantics (arrays cannot be assigned or passed). An array expression can implicitly degrade to a pointer rvalue in some situations; but in this case, you are taking the address, which needs an lvalue, so it does not apply. Never confuse arrays with pointers.
This might be a bit of a basic question, but what is the difference between writing char * [] and char **? For example, in main,I can have a char * argv[]. Alternatively I can use char ** argv. I assume there's got to be some kind of difference between the two notations.
Under the circumstances, there's no difference at all. If you try to use an array type as a function parameter, the compiler will "adjust" that to a pointer type instead (i.e., T a[x] as a function parameter means exactly the same thing as: T *a).
Under the right circumstances (i.e., not as a function parameter), there can be a difference between using array and pointer notation though. One common one is in an extern declaration. For example, let's assume we have one file that contains something like:
char a[20];
and we want to make that visible in another file. This will work:
extern char a[];
but this will not:
extern char *a;
If we make it an array of pointers instead:
char *a[20];
...the same remains true -- declaring an extern array works fine, but declaring an extern pointer does not:
extern char *a[]; // works
extern char **a; // doesn't work
Depends on context.
As a function parameter, they mean the same thing (to the compiler), but writing it char *argv[] might help make it obvious to programmers that the char** being passed points to the first element of an array of char*.
As a variable declaration, they mean different things. One is a pointer to a pointer, the other is an array of pointers, and the array is of unspecified size. So you can do:
char * foo[] = {0, 0, 0};
And get an array of 3 null pointers. Three char*s is a completely different thing from a pointer to a char*.
You can use cdecl.org to convert them to English:
char *argv[] = declare argv as array of pointer to char
char **argv = declare argv as pointer to pointer to char
I think this is a little bit more than syntactic sugar, it also offers a way to express semantic information about the (voluntary) contract implied by each type of declaration.
With char*[] you are saying that this is intended to be used as an array.
With char**, you are saying that you CAN use this as an array but that's not the way it's intended to be used.
As it was mentioned in the other answers, char*[] declares an array of pointers to char, char** declares a pointer to a pointer to char (which can be used as array).
One difference is that the array is constant, whereas the pointer is not.
Example:
int main()
{
char** ppc = NULL;
char* apc[] = {NULL};
ppc++;
apc++; /* this won't compile*/
return 0;
}
This really depends on the context of where the declarations occur.
Outside of a function parameter definition, the declaration
T a[];
declares a as an unknown-sized array of T; the array type is incomplete, so unless a is defined elsewhere (either in this translation unit or another translation unit that gets linked) then no storage is set aside for it (and you will probably get an "undefined reference" error if you attempt to link, although I think gcc's default behavior is to define the array with 1 element) . It cannot be used as an operand to the sizeof operator. It can be used as an operand of the & operator.
For example:
/**
* module1.c
*/
extern char *a[]; /* non-defining declaration of a */
void foo()
{
size_t i = 0;
for (i = 0; a[i] != NULL; i++)
printf("a[%lu] = %s\n", (unsigned long) i, a[i++]);
}
module1.c uses a non-defining declaration of a to introduce the name so that it can be used in the function foo, but since no size is specified, no storage is set aside for it in this translation unit. Most importantly, the expression a is not a pointer type; it is an incomplete array type. It will be converted to a pointer type in the call to printf by the usual rules.
/**
* module2.c
*/
char *a[] = {"foo", "bar", "bletch", "blurga", NULL}; /* defining declaration of a */
int main(void)
{
void foo();
foo();
return 0;
}
module2.c contains a defining declaration for a (the size of the array is computed from the number of elements in the initializer), which causes storage to be allocated for the array.
Style note: please don't ever write code like this.
In the context of a function parameter declaration, T a[] is synonymous with T *a; in both cases, a is a pointer type. This is only true in the context of a function parameter declaration.
As Paul said in the comment above, it's syntactic sugar. Both char* and char[] are the same data type. In memory, they will both contain the address of a char.
The array/index notation is equivalent to the pointer notation, both in declaration and in access, but sometimes much more intuitive. If you are creating an array of char pointers, you may want to write it one way or another to clarify your intention.
Edit: didn't consider the case Jerry mentioned in the other answer. Take a look at that.
char *ptr[2]={"good","bad"}; //Array of ptr to char
char **str; //Refer ptr to ptr to char
int i;
//str = &ptr[0]; //work
str = ptr;
for(i=0;i<2;i++) printf("%s %s\n",ptr[i],str[i]);
Its o/p same. Using that we can easily understand.
In the C program below, I don't understand why buf[0] = 'A' after I call foo. Isn't foo doing pass-by-value?
#include <stdio.h>
#include <stdlib.h>
void foo(char buf[])
{
buf[0] = 'A';
}
int main(int argc, char *argv[])
{
char buf[10];
buf[0] = 'B';
printf("before foo | buf[0] = %c\n", buf[0]);
foo(buf);
printf("after foo | buf[0] = %c\n", buf[0]);
system("PAUSE");
return 0;
}
output:
before foo | buf[0] = 'B'
after foo | buf[0] = 'A'
void foo(char buf[])
is the same as
void foo(char* buf)
When you call it, foo(buf), you pass a pointer by value, so a copy of the pointer is made.
The copy of the pointer points to the same object as the original pointer (or, in this case, to the initial element of the array).
C does not have pass by reference semantics in the sense that C++ has pass by reference semantics. Everything in C is passed by value. Pointers are used to get pass by reference semantics.
an array is just a fancy way to use a pointer. When you pass buf to the function, you're passing a pointer by value, but when you dereference the pointer, you're still referencing the string it points to.
Array as function parameter is equivalent to a pointer, so the declaration
void foo( char buf[] );
is the same as
void foo( char* buf );
The array argument is then decayed to the pointer to its first element.
Arrays are treated differently than other types; you cannot pass an array "by value" in C.
Online C99 standard (draft n1256), section 6.3.2.1, "Lvalues, arrays, and function designators", paragraph 3:
Except when it is the operand of the sizeof operator or the unary & operator, or is a
string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
the array object and is not an lvalue. If the array object has register storage class, the
behavior is undefined.
In the call
foo(buf);
the array expression buf is not the operand of sizeof or &, nor is it a string literal being used to initialize an array, so it is implicitly converted ("decays") from type "10-element array of char" to "pointer to char", and the address of the first element is passed to foo. Therefore, anything you do to buf in foo() will be reflected in the buf array in main(). Because of how array subscripting is defined, you can use a subscript operator on a pointer type so it looks like you're working with an array type, but you're not.
In the context of a function parameter declaration, T a[] and T a[N] are synonymous with T *a, but this is only case where that is true.
*char buf[] actually means char ** so you are passing by pointer/reference.
That gives you that buf is a pointer, both in the main() and foo() function.
Because you are passing a pointer to buf (by value). So the content being pointed by buf is changed.
With pointers it's different; you are passing by value, but what you are passing is the value of the pointer, which is not the same as the value of the array.
So, the value of the pointer doesn't change, but you're modifying what it's pointing to.
arrays and pointers are (almost) the same thing.
int* foo = malloc(...)
foo[2] is the same as *(foo+2*sizeof(int))
anecdote: you wrote
int main(int argc, char *argv[])
it is also legal (will compile and work the same) to write
int main(int argc, char **argv)
and also
int main(int argc, char argv[][])
they are effectively the same. its slightly more complicated than that, because an array knows how many elements it has, and a pointer doesn't. but they are used the same.
in order to pass that by value, the function would need to know the size of the argument. In this case you are just passing a pointer.
You are passing by reference here. In this example, you can solve the problem by passing a single char at the index of the array desired.
If you want to preserve the contents of the original array, you could copy the string to temporary storage in the function.
edit: What would happen if you wrapped your char array in a structure and passed the struct? I believe that might work too, although I don't know what kind of overhead that might create at the compiler level.
please note one thing,
declaration
void foo(char buf[])
says, that will be using [ ] notation. Not which element of array you will use.
if you would like to point that, you want to get some specific value, then you should declare this function as
void foo(char buf[X]); //where X would be a constant.
Of course it is not possible, because it would be useless (function for operating at n-th element of array?). You don't have to write down information which element of array you want to get. Everything what you need is simple declaration:
voi foo(char value);
so...
void foo(char buf[])
is a declaration which says which notation you want to use ( [ ] - part ), and it also contains pointer to some data.
Moreover... what would you expect... you sent to function foo a name of array
foo(buf);
which is equivalent to &buf[0]. So... this is a pointer.
Arrays in C are not passed by value. They are not even legitimate function parameters. Instead, the compiler sees that you're trying to pass an array and demotes it to pointer. It does this silently because it's evil. It also likes to kick puppies.
Using arrays in function parameters is a nice way to signal to your API users that this thing should be a block of memory segmented into n-byte sized chunks, but don't expect compilers to care if you spell char *foo char foo[] or char foo[12] in function parameters. They won't.