Converting char * to char * const * - c

Do excuse me to the basic"ness" of this question. I am at a loss with pointers at times. I have a char * but I need to convert it to a char * const * to be able to correctly use it in the fts() function. How do i do that?
Thanks

You are not supposed to do that kind of conversion, because the types are not compatible.
About pointers and pointers to pointers
char * is a pointer to a string of characters, whereas char ** is an pointer to a pointer to a string of characters. (the const is a bonus). This probably means that instead of supplying a string of characters, you should provide an array of string of characters.
Those two things are clearly incompatible. Don't mix them with a cast.
About the fts_* API
To find the solution to your problem, we need to read the fts_* function API (e.g. at http://linux.die.net/man/3/fts), I see that:
FTS *fts_open(char * const *path_argv, int options,
int (*compar)(const FTSENT **, const FTSENT **));
with your char * const * parameter path_argv, the description explains:
[...] If the compar() argument is NULL, the directory traversal order is in the order listed in path_argv for the root paths [...]
which confirms that the fts_open function is really expected a collection of paths, not one only path.
So I guess you need to pass to it something like the following:
char *p[] = { "/my/path", "/my/other/path", "/another/path", NULL } ;
About the const
Types in C and C++ are read from right to left. So if you have:
char * : pointer to char
char const * : pointer to const char (i.e. you can't modify the pointed string, but you can modify the pointer)
const char * : the same as char const *
char * const : const pointer to char (i.e. you can modify the pointed string, but you can't modify the pointer)
char ** : pointer to pointer to char
char * const * : pointer to const pointer to char (i.e. you can modify the pointer, and you can modify the strings of char, but you can't modify the intermediary pointer
It can be confusing, but reading them in the right-to-left order will be clear once you are more familiar with pointers (and if you programming in C or C++, you want to become familiar with pointers).
If we go back to the initial example (which sends a bunch of warnings on gcc with C99) :
char ** p = { "/my/path", "/my/other/path", "/another/path", NULL } ;
I played with the API, and you can feed it your paths two ways:
char * p0 = "/my/path" ;
char * p1 = "/my/other/path" ;
char * p2 = "/another/path" ;
/* with a fixed-size array */
char * pp[] = {p0, p1, p2, NULL} ;
FTS * fts_result = fts_open(pp, 0, NULL);
Edit 2011-11-10: snogglethorpe rightfully commented this solution is not a C89 valid solution, even if it compiles successfully with gcc (excluding pendantic + C89 flags). See Error: initializer element is not computable at load time for more info on that
or:
/* with a malloc-ed array */
char ** pp = malloc(4 * sizeof(char *)) ;
pp[0] = p0 ;
pp[1] = p1 ;
pp[2] = p2 ;
pp[3] = NULL ;
FTS * fts_result2 = fts_open(pp, 0, NULL);
free(pp) ;
Edit
After reading others answers, only two of them (mkb and moshbear) avoid the "just cast the data" error.
In my own answer, I forgot the NULL terminator for the array (but then I don't know the Linux API, nor the fts_* class of functions, so...)

I'm assuming you're talking about fts_open:
FTS *fts_open(char * const *path_argv, int options,
int (*compar)(const FTSENT **, const FTSENT **));
What it's wanting of you is an array of const char* pointers, ie. an array of strings. The const is there just to tell you that it's not going to modify your strings, and gives you the opportunity to pass const strings.
Non-const variables can be treated as const, however you shouldn't usually treat them the other way around.
The first argument is just like argv passed to main, you could just have:
char *path_argv[] = { "/first_path/", "/second_path/", NULL };
It's important that the last element is NULL to indicate the end of the array.
Note also that path_argv could also be declared as:
char **path_argv
OR*
char * const *path_argv
Any of these are suitable types to be passed as the first argument to fts_open. You do, however, obviously have to initialize it differently than the above, but those are other ways you can declare path_argv. I made that unclear previously.
And then just fts_open(path_argv, options, compar), where options is your options, and compar is your compare function.

You need to make a second array, which is NULL-terminated (because fts()'s first argument is argv).
E.g.
char *const buf2[2] = { buf, NULL };
fts(buf2);

Related

Using (char **) vs. (const * char *) vs. (const char **)

I'm trying to wrap my head around the different qualifiers for an array of pointers, or pointer to a pointer. What would be the difference between the following three declarations (the last one of which I think is wrong, but I'm not sure why):
char ** strings;
const * char * strings / char * const * strings (?);
const char ** strings;
When would one be used over another? And why does the third one (I think?) not make sense at all?
The const qualifier marks an object as immutable, that is "read-only", but you knew that most probably.
char ** strings;
strings is a mutable pointer to a mutable pointer to a mutable character. None of them is const obviously.
const * char * strings;
is syntactically wrong.
char * const * strings;
strings is a mutable pointer to an immutable pointer to a mutable character.
const char ** strings;
strings is a mutable pointer to a mutable pointer to an immutable character.
This makes sense if you need such a variable.

Running execvp from 2D array parameter

I'm attempting to run execvp using the data from a char[][] type (aka an array of strings). Now I know that execvp() takes a pointer to a string as its first parameter and then a pointer to an array of strings as its second - in fact I have even used it successfully before as such - however I cannot seem to get the correct combination of pointers & strings to get it to work out below - whatever I try is deemed incompatible!
Any help very grateful :) - I've removed my headers to compact down the code a bit!
struct userinput {
char anyargs[30][30]; //The tokenised command
};
int main() {
struct userinput input = { { { 0 } } }; //I believe is valid to set input to 0's
struct userinput *inPtr = &input; //Pointer to input (direct access will be unavailable)
strcpy(inPtr->anyargs[0], "ls"); //Hard code anyargs to arbitary values
strcpy(inPtr->anyargs[1], "-lh");
char (*arrPointer)[30]; //Pointer to an array of char *
arrPointer = &(inPtr->anyargs[0]);
printf("arrPointer[0]: %s, arrPointer[1]: %s\n", arrPointer[0],
arrPointer[1]);
printf("At exec case; ");
execvp( arrPointer[0], arrPointer);
perror("Command not recognised"); //Prints string then error message from errno
return 0;
}
There is no such thing as char[][] in C. execvp requires an array of pointers to const char. This can be written as either char * const * or char * const [].
You however have an array of 30-characters-long arrays, not an array of pointers. The two types are not compatible, not interchangeable, and not convertible one to another in either direction.
In this line
char (*arrPointer)[30]; //Pointer to an array of char *
you attempt to declare a pointer to an array of char*, incorrectly. What you have declared instead is a pointer to char[30], which is very different from what execvp expects.
The next line
arrPointer = &(inPtr->anyargs[0]);
purports to initialize a pointer to an array of char* with a pointer to char[30], which cannot possibly be correct even if you declare a pointer to an array of char*, because the right hand side of the assignment is not a pointer to an array of char*, it's a pointer to char[30] and no sequence of casts, indices, addresses and dereferences will turn one to the other.
An array of 30 pointers to char is declared like this:
char* arguments[30];
A dynamically-sized array of pointers to char is made like this:
char** arguments = calloc (nargs, sizeof(char*));
You need to use one of those if you want to call execvp.
In either case each pointer in the array of pointers must be initialized to point to an individual NUL-terminated character array (possibly to elements of your char[30][30] array) and the last pointer (one after all the argumenrs we want to pass) must be set to NULL. (I wonder how you expected to find a NULL in a char[30][30]).
The execvp() expects as second argument a char *const argv[]. This means an array of pointers to char. This is different from a char[30][30] which is represented in memory as 30x30 contiguous chars (so no pointer).
To solve this, define your structure
struct userinput {
char *anyargs[30]; //space for 30 char* pointers
};
You could as well define anyargs as char** and initalize if dynamically with (char**)calloc(number_of_args+1,sizeof(char*))
Later, assign directly the pointers:
inPtr->anyargs[0] = "ls"; //Hard code (or use strdup() )
inPtr->anyargs[1] = "-lh";
inPtr->anyargs[2] = NULL; // end of the argument list !!!
char **arrPointer; //Pointer to an array of char *
arrPointer = inPtr->anyargs;
Edit: Caution: "The array of pointers must be terminated by a NULL pointer.".

const char * VS char const * const (Not about what is const)

So, I know the differences between char const *, char * const, and char const * const. Those being:
char* the_string : I can change the char to which the_string points,
and I can modify the char at which it points.
const char* the_string : I can change the char to which the_string
points, but I cannot modify the char at which it points.
char* const the_string : I cannot change the char to which the_string
points, but I can modify the char at which it points.
const char* const the_string : I cannot change the char to which
the_string points, nor can I modify the char at which it points.
(from const char * const versus const char *?)
Now, my question is: Let's say I'm writing a function that would not modify the C string that is passed to it, for example:
int countA(??? string) {
int count = 0;
int i;
for (i=0; i<strlen(string); i++) {
if (string[i] == 'A') count++;
}
return count;
}
Now, what should the header be?
int countA(char const * string);
int countA(char const * const string);
My feeling is that I should use the second one, because I'm not going to modify the pointer itself, neither the contents of the array. But when I look to the header of standard functions they use the first one. Example
char * strcpy ( char * destination, const char * source );
Why?
(In fact char const * doesn't really make sense to me, because if you're thinking about the abstract string, either you are not modifying the string (so, char const * const because you are not modifying the pointer, neither the contents) or you will modify the string (so just char * because, you may modify the contents and you may need to allocate more memory, so you may need to modify the pointer)
I hope someone can make all this clear to me. Thanks.
In this case, it does not matter whether the pointer itself is const or not, because it is passed by-value anyway: Whatever strcpy does to source will not affect the caller's variable, because strcpy will operate on a copy of the caller's source on the stack, not the original. Note I am talking about the pointer value, not what the pointer points to, which should obviously not be changed since it is the source parameter.
char dest[10];
char const * source = "Hello";
strcpy( dest, source );
// no matter what strcpy does, the value of source will be unchanged
Within strcpy, you need to iterate pointers over the arrays pointed to by destination and source anyway. Not declaring the parameters as const allows the function to use the values from the stack directly, without copying / casting them first.
Having const char * represents a contract. It's a promise the function will not use that pointer to modify the contents passed by the user. Whether the pointer itself is constant or not is less valuable.
So, for the caller, whether the pointer itself is const or not makes no difference whatsoever.
In many implementations "string" functions regularly modify the passed pointer without modifying the contents. If the spec (the C standard) would mandate the pointer itself to be constant, it would be a limiting factor for all implementations, without providing any benefit for the caller.
As a side note, I think you shouldn't make everything const and then work your way around it. Just make stuff const if it feels the function shouldn't have reason to change it. In short, don't go const-mad, it's not a silver bullet and can be a recipe for frustration.
When you declare a function parameter as const char * const, it is not different to your callers from const char *: they could not care less what you do with that pointer, because to them it is all "pass by value" anyway.
The second const is there for you, not for your users. If you know that you are not going to modify that pointer, then by all means declare it const char * const: it is going to help you and others who maintain your code to catch errors later.
As for the standard library, my guess is that they did not want to make it const char * const because they wanted an ability to modify the poitners:
char * strcpy ( char * destination, const char * source ) {
char *res = destination;
while (*destination++ = *source++)
;
return res;
}
The non-defining declarations:
int countA(char const * string);
int countA(char const * const string);
int countA(char const * foobar);
int countA(char const *);
are all equivalent. The string parameter names (in effect) a local variable inside the implementation of countA. It's none of the caller's business whether the implementation modifies that variable or not, and it doesn't affect the signature of the function.
It is the caller's business whether the function modifies the referand of string, so the first const is important. It is slightly the caller's business what the variable is named, but only because the convention is to name parameters in declarations as a hint what they're used for. Documentation is the way to completely convey the meaning of each parameter, not its name.
If you want a rule: omit the second const, because it clutters the declaration while telling the caller nothing of any use.
You could include it in the function definition, but there are some problems with doing so. You either need to keep the header up to date with the definition (in which case you'll sometimes find yourself changing the header due to a change in implementation details that doesn't affect callers). Or else you have to accept that the header doesn't match the definition, which will occasionally upset people who see:
int countA(char const * const string) {
return 0;
}
and search the headers for int countA(char const * const string), or vice-versa see the header and search the source. They need a smarter search term.
char const *s : s is a pointer to const char.
char *const s : s is a constant pointer to char.
When s is a function parameter, the first notation is more useful than the second.
With char const *, you can't modify the pointed value.
With char *const, you can't modify the value of your pointer. It is like int const in function parameters : you can't do operations directly onto your parameter. It doesn't change anything for the call function. (now, it's almost useless for the compiler, but it's meaningful for programmers)

how to set char array to string in c

so i have a struct call Process_Info
struct Process_Info {
char name[128];
int pid;
int parent_pid;
int priority;
int status;
};
and an array of Process_Info call info. I set pid in info to an integer, it works but when I try to set name in info to "{kernel}" like this
info[i].name="{kernel}";
and it give me incompatible type in assignment error. I search online it seem i can do this, like in http://www.cs.bu.edu/teaching/cpp/string/array-vs-ptr/, they did char label[] = "Single"; So what am i doing wrong?
The short answer: A C compiler will bake constant strings into the binary, so you need to use strncpy (or strcpy if you aren't worried about security) to copy "{kernel}" into info[i].name.
The longer answer: Whenever you write
char label[] = "Single";
the C compiler will bake the string "Single" into the binary it produces, and make label into a pointer to that string. In C language terms, "Single" is of type const char * and thus cannot be changed in any way. However, you cannot assign a const char * to a char *, since a char * can be modified.
In other words, you cannot write
char label[] = "Single";
label[0] = "T";
because the compiler won't allow the second line. However, you can change info[i].name by writing something like
info[i].name[0] = '[';
because info[i].name if of type char *. To solve this problem, you should use strncpy (I referenced a manual page above) to copy the string "{Kernel}" into info[i].name as
strncpy(info[i].name, "{Kernel}", 256);
info[i].name[255] = '\0';
which will ensure that you don't overflow the buffer.
I think you may be mistaken. The way you would assign this would be one char at a time like so...
name[] = {'a','b','c','d'};

Why is the param of strlen a "const"?

I'm learning the C language.
My question is:
Why is the param of strlen a "const" ?
size_t strlen(const char * string);
I'm thinking it's because string is an address so it doesn't change after initialization. If this is right, does that mean every time you build a function using a pointer as a param, it should be set to a constant ?
Like if I decide to build a function that sets an int variable to its double, should it be defined as:
void timesTwo(const int *num)
{
*num *= 2;
}
or
void timesTwo(int *num)
{
*num *= 2;
}
Or does it make no difference at all ?
C string is a pointer to a zero-terminated sequence of characters. const in front of char * indicates to the compiler and to the programmer calling the function that strlen is not going to modify the data pointed to by the string pointer.
This point is easier to understand when you look at strcpy:
char * strcpy ( char * destination, const char * source );
its second argument is const, but its first argument is not. This tells the programmer that the data pointed to by the first pointer may be modified by the function, while the data pointed to by the second pointer will remain constant upon return from strcpy.
The parameter to strlen function is a pointer to a const because the function is not expected to change what the pointer points to - it is only expected to do something with the string without altering it.
In your function 'timesTwo', if you intend to change the value that 'num' points to, you should not pass it in as a pointer-to-const. So, use the second example.
Basically, the function is promising that it will not modify the contents of of the input string through that pointer; it says that the expression *string may not be written to.
Here are the various permutations of the const qualifier:
const char *s; // s may be modified, *s may not be modified
char const *s; // same as above
char * const s; // s may not be modified, *s may be modified
const char * const s; // neither s nor *s may be modified
char const * const s; // same as above

Resources