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.".
Related
I wish to split a "string" by the character ','.
The string holds a GPS NMEA encoded string, but that is of no matter.
My problem is that sometimes the parameter from the function that processes this char array is empty... Like nothing is in the array.
How should I correctly pass a "char string[]" to a function so that I may operate on a that parameter as I sent it(as a char array, not a char pointer to an array).
I also need to specify that I'm using mikroC for PIC.
Here is my code as of right now:
char* GPS_sateliti;
char CsatInView[] =
"$GPGSV,3,2,11,14,25,170,00,16,57,208,39,18,67,296,40,19,40,246,00*74";
GPS_sateliti = GrupeazaDupaVirgule(CsatInView, 2);
char* GrupeazaDupaVirgule( char deGasit[],int nrVirgule ){
int cVirgule = 1;
char* pch = strtok (deGasit,",");
while (pch != 0)
{
pch = strtok (0, ",");
cVirgule++;
if(nrVirgule == cVirgule){
break;
}
}
return pch;
}
The function that operates on the char array received as a parameter in debug mode, before entering the function the char array is fine, after entering it, it seems to be empty
It may be that I should receive a pointer to an array of chars??
Any sort of advice is welcome.
Thank you
How should I correctly pass a "char string[]" to a function so that I may operate on a that parameter as I sent it(as a char array, not a char pointer to an array).
You can't. A function parameter of an array type always decays as the corresponding pointer type.
There are two idiomatic solutions to this.
1. a sentinel:
The last value in the array is a special value that marks the end. This is done in C with strings. They always end with a \0 character, that is guaranteed not to occur inside the string. The function can search for that character to know where the data ends.
(Note: with this info I have to add I'm not sure what your problem is. If you pass an "empty string", as literally "", the \0 will be there, so you shouldn't have a problem)
2. explicitly passing the size:
instead of just
void foo(int bar[]);
you define a function
void foo(size_t barSize, int bar[]);
The caller knows the size of the array, so it can just pass it along.
With a pointer :
char* arr;
yourFunction(arr);
If you wish to initialize it before :
char* arr = malloc(51 * sizeof(char)); // Allocate a memory place of 50 because strings are null terminated in C
yourFunction(arr);
An other way to allocate memory to an array :
char* arr = calloc(50, sizeof(char)); // Allocate 50 memory place which size if the size of a char
With a string :
char arr[50];
char* ptr = arr;
yourFunction(ptr);
You have to know that it is impossible in C to know the size of an array when using pointer. The only thing you can do is to parse the size of the string as a parameter :
size_t size = 50;
char arr[size];
char* ptr = arr;
yourFunction(ptr, size);
If you wish to understand in detail how pointer works and how to iterate them, may be this post can help you. I think it is very interesting.
Globally, you iterate through an array via a pointer like this :
for ( int i = 0; i < size; i++)
printf("Current pointed value in the array : %c\n", ptr[i]); // or arr[i]
I guess you understand why giving the size of a pointed array as a parameter is important. Sometimes you can avoid using this parameter like this :
for ( int i = 0; i != '\0'; i++) // Because strings are null-terminated in C.
// Do something
I am writing a simple function in C that should build a char array from string "abc" – so it should build {'a','b','c'} – and return a pointer to that array. Here is my code for this function:
char * makeArr()
{
static char arr[3];
sprintf(arr, "%s\n", "abc");
return arr;
}
Problems occur when I call this method in main:
int main(int argc, char *argv[])
{
char *arr[3];
arr = makeArr();
return 0;
}
The compiler is complaining about casting / conflicting types. I've been playing with pointers, casting and dereferencing for quite a while now, but can't seem to get it to work. Please let me know where my logic is wrong.
Hmm ... there are several errors in this code. Let's start with the most obvious your compiler complains about:
char *arr[3];
This line declares arr to be an array of three pointers to char. What you return from your function is a single pointer to a char -> doesn't match.
Next:
static char arr[3];
sprintf(arr, "%s\n", "abc")
Here you reserve 3 chars. the sprintf() will write 5 chars. %s is replaced by the 3 characters in your string literal "abc". You add a newline character and then a 0 is added as the marker for the end of the "string". Makes 5. This btw is undefined behavior. You write past the end of your array. Code like this can be compiled, but there's no guarantee at all about what will happen at runtime.
Doing a cut here. You should read about arrays and pointers in C. If the text you're reading claims they are the same ... stop right there and find a better text. They aren't.
I'll try to explain this here briefly, so it's suitable for the Q&A style.
An array in C indeed is a contiguous space of several values. char arr[3] means a variable that holds 3 chars.
On the other hand, a char * is just a pointer pointing to a char -- this could be the first element of an array.
In C, you can't pass arrays as function parameters, and you can't return arrays from a function. Trying to do so leads to an implicit conversion: What is actually passed is a pointer to the first element of that array.
I think the last bit of information missing is what a string literal in C is: it's an array (anonymous, e.g., it doesn't have a name) containing all the characters in the double quotes plus a 0 appended. The 0 marks the end of a "string" in C.
In an expression, a string literal evaluates to a pointer to the first element.
So, something like this:
char *foo = "bar";
will lead to foo pointing to the b of the array. It's like writing
static const char no_name_0[] = { 'b', 'a', 'r', 0 };
char *foo = &(no_name_0[0]);
Among other things, you confused:
char arr[3]; // array of 3 chars.
and,
char *arr[3]; // array of 3 pointers to char.
In main(), you should only write char *arr;
Firstly, char arr[3]; is too snall to store "abc\n". It must have at least 5 elements including terminating null-character.
Then, char *arr[3]; is a 3-element array of char*.
You should assign makeArr()'s return value (it has char* type) to arr[0] or another element, or you should change the type of arr in main function to char*, which is the same type as makeArr()'s return value.
Moreover, this makeArr() doesn't make any array and returns (a pointer to) the existing array. Yoy should use malloc() to "make an array".
UPDATE:
Assigning a value of char* to the array char arr[10]; seems invalid in C.
You should use strcpy() or strncpy() (safer than strcpy()) to copy the string stored in the array between arrays.
Pass the array as an argument and modify it in the called function, would be easier. If you're statically creating the array and there's no need to allocate memory, don't, just pass around your pointers to the functions to be modified by reference
void makeArr(char arr[]){
sprintf(arr, "%s\n", "abc");
}
Simply pass the existing declared array to the makeArr function...
int main(int argc, char *argv[]) {
char arr[10];
makeArr(arr);
return 0;
}
You couldn't assign the result of makeArr to arr. I guess that's your casting error. Oversimplifying, arr points to the place on the stack where the array of 10 characters is allocated. So, I'd pass in arr to makeArr as a char*. So, you'd end up with something like this:
#include <stdio.h>
char * makeArr(char *arr)
{
sprintf(arr, "%s\n", "abc");
return arr;
}
int main(int argc, char *argv[])
{
char arr[10];
makeArr(arr);
printf("%s\n", arr);
return 0;
}
I would like to assign a character in a string to the first character of string in array of strings, equivalently I would like to assign a pointer in an array of pointers to the value of another pointer.
I have tried the following:
char ** array=malloc(sizeof(char*)*10);
char * str="like";
*(array[0])=*str;
*(array[0])=str[0];
**(array)=*str;
**(array)=str[0];
These seem like they are assigning the value of value of the first pointer.
I keep getting a segmentation fault error.
I realized that I was misunderstanding what happens when an array of pointers is created. I assumed that C actually created the pointers in an array and didn't just allocate space for them.
The fix:
char ** array = malloc(sizeof(char *) * 10);
char tok = *ts; /* create character that has value of a pointer */
char *token =&tok; /* create new pointer that points to same value as *ts but in a different address */
array[0]=token; /* assign the pointer */
In a program I am writing I made a Tokenize struct that says:
TokenizerT *Tokenize(TokenizerT *str) {
TokenizerT *tok;
*tok->array = malloc(sizeof(TokenizerT));
char * arr = malloc(sizeof(50));
const char *s = str->input_strng;
int i = 0;
char *ds = malloc(strlen(s) + 1);
strcpy(ds, s);
*tok->array[i] = strtok(ds, " ");
while(*tok->array[i]) {
*tok->array[++i] = strtok(NULL, " ");
}
free(ds);
return tok;
}
where TokenizeT is defined as:
struct TokenizerT_ {
char * input_strng;
int count;
char **array[];
};
So what I am trying to do is create smaller tokens out of a large token that I already created. I had issues returning an array so I made array part of the TokenizerT struct so I can access it by doing tok->array. I am getting no errors when I build the program, but when I try to print the tokens I get issues.
TokenizerT *ans;
TokenizerT *a = Tokenize(tkstr);
char ** ab = a->array;
ans = TKCreate(ab[0]);
printf("%s", ans->input_strng);
TKCreate works because I use it to print argv but when i try to print ab it does not work. I figured it would be like argv so work as well. If someone can help me it would be greatl appreciated. Thank you.
Creating the Tokenizer
I'm going to go out on a limb, and guess that the intent of:
TokenizerT *tok;
*tok->array = malloc(sizeof(TokenizerT));
char * arr = malloc(sizeof(50));
was to dynamically allocate a single TokenizerT with the capacity to contain 49 strings and a NULL endmarker. arr is not used anywhere in the code, and tok is never given a value; it seems to make more sense if the values are each shifted one statement up, and corrected:
// Note: I use 'sizeof *tok' instead of naming the type because that's
// my style; it allows me to easily change the type of the variable
// being assigned to. I leave out the parentheses because
// that makes sure that I don't provide a type.
// Not everyone likes this convention, but it has worked pretty
// well for me over the years. If you prefer, you could just as
// well use sizeof(TokenizerT).
TokenizerT *tok = malloc(sizeof *tok);
// (See the third section of the answer for why this is not *tok->array)
tok->array = malloc(50 * sizeof *tok->array);
(tok->array is not a great name. I would have used tok->argv since you are apparently trying to produce an argument vector, and that's the conventional name for one. In that case, tok->count would probably be tok->argc, but I don't know what your intention for that member is since you never use it.)
Filling in the argument vector
strtok will overwrite (some) bytes in the character string it is given, so it is entirely correct to create a copy (here ds), and your code to do so is correct. But note that all of the pointers returned by strtok are pointers to character in the copy. So when you call free(ds), you free the storage occupied by all of those tokens, which means that your new freshly-created TokenizerT, which you are just about to return to an unsuspecting caller, is full of dangling pointers. So that will never do; you need to avoid freeing those strings until the argument vector is no longer needed.
But that leads to another problem: how will the string be freed? You don't save the value of ds, and it is possible that the first token returned by strtok does not start at the beginning of ds. (That will happen if the first character in the string is a space character.) And if you don't have a pointer to the very beginning of the allocated storage, you cannot free the storage.
The TokenizerT struct
char is a character (usually a byte). char* is a pointer to a character, which is usually (but not necessarily) a pointer to the beginning of a NUL-terminated string. char** is a pointer to a character pointer, which is usually (but not necessarily) the first character pointer in an array of character pointers.
So what is char** array[]? (Note the trailing []). "Obviously", it's an array of unspecified length of char**. Because the length of the array is not specified, it is an "incomplete type". Using an incomplete array type as the last element in a struct is allowed by modern C, but it requires you to know what you're doing. If you use sizeof(TokenizerT), you'll end up with the size of the struct without the incomplete type; that is, as though the size of the array had been 0 (although that's technically illegal).
At any rate, that wasn't what you wanted. What you wanted was a simple char**, which is the type of an argument vector. (It's not the same as char*[] but both of those pointers can be indexed by an integer i to return the ith string in the vector, so it's probably good enough.)
That's not all that's wrong with this code, but it's a good start at fixing it. Good luck.
main(){
char *cmd1[20] = {NULL};
int x = parse_command(cmd1);
printf("%s\ ",cmd1[0]);
}
parse_command(char *inTempString){
char tempString[256];
(call to function that assigns a string to tempString)
cmd1[0] = tempString;
}
There is a problem when printing out the cmd1[0] within main. I am pretty sure that it is a dangling pointer error. I don't really know how to go about fixing it.
There are two issues with your program.
First, when you say:
char *cmd1[20] = {NULL};
cmd1 is an array of 20 pointers to char. This means that cmd1[i] for i in [0,20) is a pointer to char.
There is a rule in C that says that passing an array to a function only passes the pointer to the first element of the array to the function. I.e., if you had code like:
int ai[20];
f(ai);
then the type of ai in the function call f(ai); is int * and the pointer passed to f() is equal to &ai[0], the first element of ai.
So, when you do:
parse_command(cmd1);
you immediately know that the "thing" passed to parse_command() is &cmd1[0], i.e., a pointer to the first element of cmd1. Since cmd1[0] is of type char *, you are passing a char ** to parse_command. Therefore, your declaration:
parse_command(char *inTempString);
is wrong, you should do:
parse_command(char **inTempString);
to match your call. This assumes that parse_command() will parse more than one value in cmd1. If that is the case, you should also pass the number of elements in cmd1 to parse_commnd()—since it can't know how many elements cmd1 has.
Your second problem is that you can't return the address of a local variable from a function in C. As above, in addition to a function call, returning an array in C, or assigning something to an array in C also makes the name of an array "decay" to a pointer to its first element.
So given your function:
/* changed inTempString to cmd1 because that's what you probably meant */
int parse_command(char *cmd1)
{
char tempString[256];
/* call to function that assigns a string to tempString */
cmd1[0] = tempString;
/* you need to return an int from here */
}
the tempString in the assignment to cmd1[0] is actually &tempString[0], i.e., a pointer to the first element of tempString. But since tempString is destroyed as soon as the function returns, the pointer becomes invalid. You can't use the value later.
In fact, in C, the name of an array decays to a pointer to its first element in all cases, except:
when used as an operand to sizeof operator, and
when used as an operand to the address-of (&) operator
To be more precise, in object contexts, the name of an array doesn't decay to a pointer, and in value contexts, it decays to a pointer. See this for more details.
Now, how should you fix your second issue? It depends—you can either allocate memory dynamically in parse_command(), and assign that memory to cmd1[0], or you can make tempString static in the function. Since static variables in a function are not destroyed when a function returns, you can continue using a pointer to it. Dynamic allocation is more work—you need to worry about allocation failure and you need to remember to free the pointer when done. static array is easier, but you have to be careful because another call to parse_command will overwrite the array, making it less-generic.
Assuming you want to go the "dynamic memory" route, here is a scheme that you could use:
#include <stdio.h> /* printf */
#include <stdlib.h> /* malloc and free */
int main(void) /* main returns int */
{
char *cmd1[20] = {NULL};
/* number of commands. "sizeof cmd1" is the number of bytes
used by the cmd1 array, and "sizeof cmd1[0]" is the number
of bytes used by one element of the array. The division
gives you the number of elements. This is 20 of course
but doing it this way makes sure that changing "20" to any
number works. */
size_t ncmds = sizeof cmd1 / sizeof cmd1[0];
/* pass the number of commands to "parse_command", since
it can't know otherwise */
int x = parse_command(cmd1, ncmds);
int i;
for (i=0; i < x; ++i) {
printf("%s ", cmd1[i]);
free(cmd1[i]);
}
return 0; /* return a value from main */
}
int parse_command(char **cmd1, size_t ncmds)
{
char *tempString; /* we will malloc this */
int i; /* the number of mallocs done successfully */
tempString = malloc(...);
if (tempString == NULL) {
/* failure, handle gracefully */
} else {
++i; /* make sure i doesn't exceed or equal ncmds */
}
cmd1[0] = tempString;
/* do the above as many times as you need */
return i; /* the number successfully assigned to */
}
You're declaring cmd1 in main as a char** -- that is, a pointer to pointer to char. However, you then pass it to parse_command, which you've defined as taking a char*; a pointer to char.
This only compiles because of automatic conversion of pointer-to-anything to pointer-to-char. That's a historical artifact of old versions of C that used 'char*' in place of 'void*'; in your case, it just means that the compiler is ignoring the type error that you made rather than reporting it to you.
Something like this will work:
parse_command(char **inTempString){
static char tempString[256];
strcpy(tempString,"some string you want to copy");
inTempString[0] = tempString;
}
In your code the tempString would not
exist once the function returns. You
need to keep it alive even after the
function returns. You can allocate
the space dynamically and de-allocate
later or you can declare it as
static.
Also you need to change the type
argument inTempString from char* to
char**.
You are trying to access cmd1 variable that is inside main function from parse_command.
I would say that at least the cmd1[0] will look like an integer because it is not declared withing that method.
The cmd1 is declared as array of char* but the parameter to method is char* which might be a pointer to char array but not pointer to array of char*.
The best way to copy char array into another char array is to use either memcpy,strcpy or similar methods that accept pointers to src, dest and size to be copied.
Yeah, you can't do that.
char tempString[256];
declares a variable on the stack in the function parse_command, that variable goes out of scope and pointers to it cease to be valid when parse_command returns.
You need to allocate the command string on the heap, so that it will still be valid when parse_command returns. This is one way.
parse_command(char *inTempString){
char tempString[256];
(call to function that assigns a string to tempString)
int cb = strlen(tempString)+1;
cmd1[0] = (char *)malloc(cb);
strcpy(cmd1[0], tempString);
}
You should also call free(cmd[0]) before main exits.
In addition to that, this code doesn't compile. You can't reference cmd1[0] from inside the parse_command function. You should be getting a type mismatch when you try and pass cmd1 into parse_command, If you mean to return a char* from parse_command then it should be declared to take a char** as an argument, more like this.
parse_command(char **pcmd){
char tempString[256];
(call to function that assigns a string to tempString)
int cb = strlen(tempString)+1;
pcmd[0] = (char *)malloc(cb);
strcpy(pcmd[0], tempString);
}