Setting pointer value without it being changed afterwards - c

I'm reading a string with space as a delimiter by using the strtok function.
My code looks like this:
char * pch = strtok (text," ");
int i = 0;
while (pch != NULL)
{
if (i == 0)
strcpy(name, pch);
else
others[i - 1] = pch;
pch = strtok (NULL, " ");
}
The string looks like this: TCP 1 2 3 4, and name is of char* type that I receive in my function.
I wish to assign name to be TCP (i.e. first piece before the first delimiter), but because the pch pointer proceeds, the name variable changes when pch changes. How can I assign the pch pointer value to name without it being changed when the pointer changes?

You forgot i++. You never increment i.

You never increment i so every loop ends up copying the latest value of pch into name.
You could fix it by incrementing i for each iteration of the loop:
char * pch = strtok (text," ");
int i = 0;
while (pch != NULL)
{
if (i++ == 0) // ++ is the only change from your code
strcpy(name, pch);
else
others[i - 1] = pch;
pch = strtok (NULL, " ");
}

Your description doesn't match your code.
Your code clearly copies the data (the characters) with strcpy(), not just the pointer. The latter would look like:
if (i == 0)
name = pch;
but that would still work, since you've copied the pointer to the first token, and the copy won't change.
The others array, on the other hand, is risky if the contents of text changes after the loop, since there you're only storing pointers.
EDIT: D'oh, as others point our you're failing to increment i, which might explain the strangeness. Not sure why I missed this, I guess I was too confused about the disconnect between the description and the code.

Related

C programming arrays big level

So im getting a file with strings, i want to tokenize each string whenever i come to a whitespace/newline. i am able to get the tokens seperated into delimiter strings, but im not able to copy them into an array.
int lexer(FILE* file){
char line[50];
char* delim;
int i = 0;
int* intptr = &i;
while(fgets(line,sizeof(line),file)){
printf("%s\n", line);
if(is_empty(line) == 1)
continue;
delim = strtok(line," ");
if(delim == NULL)
printf("%s\n", "ERROR");
while(delim != NULL){
if(delim[0] == '\n'){
//rintf("%s\n", "olala");
break;
}
tokenArray[*intptr] = delim;
printf("Token IN array: %s\n", tokenArray[*intptr]);
*intptr = *intptr + 1;
delim = strtok(NULL, " ");
}
if i run this i get the output :
Token IN array: 012
Token IN array: 23ddd
Token IN array: vs32
Token IN array: ,344
Token IN array: 0sdf
which is correct according to my textfile, but when i try to reprint the array at a later time in the same function and out
*intptr = *intptr + 1;
delim = strtok(NULL, " ");
}
}
printf("%s\n", tokenArray[3]);
fclose(file);
return 0;
i dont get an output, i tried writing all the contents of the array to a txt file, i got gibberish. i dont know what to do plz help
First, your pointer on i is useless. Why not using i directly?
I'll assume that from now on.
Then, the real problem: you have to allocate and copy the strings that strtok returns each time because strtok does not allocate the tokens for you, it justs points to the last one. The references are all the same, so you get last empty token
Something like this would help:
tokenArray[*intptr] = strdup(delim);
(instead of tokenArray[*intptr] = delim;) note that I have replaced the index by i. Just to i++ afterwards.
BTW I wouldn't recommend using strtok for other purposes that quick hacks. This function has a memory, so if you call several functions using it in different parts of your program, it can conflict (I made that mistake a long time ago). Check manual for strtok_r in that case (r for reentrant)
tokenArray[*intptr] = delim;
In this line, delim is a pointer to a char array of which the content is ever changing in the for loop. So in your case, the content which delim point to should be copied as content of tokenArray[*intptr], that is:
tokenArray[*intptr] = strdup(delim);

Segmentation fault on line with fgets() - C

I have this code in my program:
char* tok = NULL;
char move[100];
if (fgets(move, 100, stdin) != NULL)
{
/* then split into tokens using strtok */
tok = strtok(move, " ");
while (tok != NULL)
{
printf("Element: %s\n", tok);
tok = strtok(NULL, " ");
}
}
I have tried adding printf statements before and after fgets, and the one before gets printed, but the one after does not.
I cannot see why this fgets call is causing a segmentation failure.
If someone has any idea, I would much appreciate it.
Thanks
Corey
The strtok runtime function works like this
the first time you call strtok you provide a string that you want to tokenize
char s[] = "this is a string";
in the above string space seems to be a good delimiter between words so lets use that:
char* p = strtok(s, " ");
what happens now is that 's' is searched until the space character is found, the first token is returned ('this') and p points to that token (string)
in order to get next token and to continue with the same string NULL is passed as first argument since strtok maintains a static pointer to your previous passed string:
p = strtok(NULL," ");
p now points to 'is'
and so on until no more spaces can be found, then the last string is returned as the last token 'string'.
more conveniently you could write it like this instead to print out all tokens:
for (char *p = strtok(s," "); p != NULL; p = strtok(NULL, " "))
{
puts(p);
}
EDITED HERE:
If you want to store the returned values from strtok you need to copy the token to another buffer e.g. strdup(p); since the original string (pointed to by the static pointer inside strtok) is modified between iterations in order to return the token.

Segmentation fault when using strlen on user input string

I'm trying to understand what's wrong with my code.
I have a string composed by words inserted by user input.
I've terminated the string so it should be ok.
Then I use another cycle to reverse the direction of the words. But when I call STRLEN on the last word of the string, it gives me segmentation fault.
(the reversal part is not done yet, since i'm stuck with this problem).
Why?
Here is the code:
char *frase, c;
int i=0;
int d=1;
frase = (char*)malloc(sizeof(char));
printf("Insert phrase: ");
while(c != '\n') {
c = getc(stdin);
frase = (char*)realloc(frase,d*sizeof(char)); //dynamic allocation
frase[i] = c;
d++;
i++;
}
//at the end i terminate the string
frase[i]='\0';
printf("\nInserted phrase: %s\n",frase);
// here I start the reversal, first of all I separate all the words
char *pch;
char s[2] = " ";
int messl=0;
pch = strtok (frase,s);
printf ("%s\n",pch);
messl += 1 + strlen(pch);
printf ("Lung stringa = %d\n",messl);
char *message = (char*) malloc(messl);
while (pch != NULL) {
pch = strtok (NULL, s);
printf("%s\n",pch);
messl += 1 + strlen(pch); //in the last cycle of the loop I get the error
}
//printf ("%s\n",message);
return 0;
In your code.
while(c != '\n')
at the very first iteration, c is uninitialised. It invokes undefined behaviour to use the value of an automatic local variable which has not been initialized explicitly.
getc() returns an int which , at times, may not fit into a char. Change the type of c to int.
That said, as you mentioned in your question, that you're getting segfault from strlen(), you need check for the non-NULL value of the passed pointer to strlen(). Add the NULL-check to pch immediately after tokenizing.
The main problem is:
while (pch != NULL) {
pch = strtok (NULL, s);
printf("%s\n",pch);
messl += 1 + strlen(pch);
When strtok returns NULL, you go on to call printf and strlen on it. You need to immediately test pch upon calling strtok. For example the loop structure could be:
while ( (pch = strtok(NULL, s)) != NULL ) {
There are various other problems too, as other answerers/commentors have noted.

A Little strtok() Fun

I am not the best with pointers, so maybe you can see what I'm doing wrong.
Let's say that I have an array that was initialized like this:
char *arrayOfCommands[]={"ls -l", "wc -l"};
My goal is to get an array called char *currentCommand out of this array that looks at a specific cell of arrayOfCommands and separates the command into pieces on spaces.
My final goal would be to have a new currentCommand array on each loop that each look like this:
First Loop:
currentCommand = [ls][-l]
First Loop:
currentCommand = [wc][-l]
Here is the code I have so far:
for (i = 0; i < 2; ++i) {
char str[] = arrayOfCommands[i];
char * currentCommand;
printf ("Splitting string \"%s\" into tokens:\n",str);
currentCommand = strtok (str, " ");
while (currentCommand != NULL){
printf ("%s\n",currentCommand);
currentCommand = strtok (NULL, " ");
}
.
.
.
//Use the currentCommand array (and be done with it)
//Return to top
}
Any help would be greatly appreciated! :)
UPDATE:
for (i = 0; i < commands; ++i) {
char str[2];
strncpy(str, arrayOfCommands[i], 2);
char *currentCommand[10];
printf ("Splitting string \"%s\" into tokens:\n",str);
currentCommand = strtok (str, DELIM);
while (currentCommand != NULL){
printf ("%s\n",currentCommand);
currentCommand = strtok (NULL, DELIM);
}
}
I am getting this error: ** incompatible types in assignment**
It's talking about the "str" I'm passing the strtok function.
strtok operates by modifying the string that you pass; this is easy to miss when using some man pages. Each command in your array is a literal string: attempts to modify them will cause problems. So you'll need to make a copy of each command before using it with strtok.
Furthermore, this is an invalid initialization for an array:
char str[] = arrayOfCommands[i];
Declare str as an array of some fixed size, then use strncpy to make copies of each command before tokenizing them using strtok:
char str[MAX_COMMAND_LEN + 1];
strncpy(str, arrayOfCommands[i], MAX_COMMAND_LEN);
// ...

Compilation issues on linux

So I wrote the following code in linux(Ubuntu) using the emacs text editor it basically supposed to split the string on the delimeter passed in . When I ran it it segfaulted I ran it though GDB and it gives me an error at strcpy(which I don't invoke) but is probably done implicitly in sprintf. I didn't think I was doing anything wrong so I booted into windows and ran it through visual studio and it works fine I am new to writing C in Linux and know the problem is in the While loop where i call sprintf() (which is odd because the call outside of the loop writes without causing an error) to write the token to the array. If anyone can tell me where I am going wrong I would greatly appreciate it. Here is the code
/* split()
Description:
- takes a string and splits it into substrings "on" the
<delimeter>*/
void split(char *string, char *delimiter)
{
int i;
int count = 0;
char *token;
//large temporary buffer to over compensate for the fact that we have
//no idea how many arguments will be passed with a command
char *bigBuffer[25];
for(i = 0; i < 25; i++)
{
bigBuffer[i] = (char*)malloc(sizeof(char) * 50);
}
//get the first token and add it to <tokens>
token = strtok(string, delimiter);
sprintf(bigBuffer[0], "%s", token);
//while we have not encountered the end of the string keep
//splitting on the delimeter and adding to <bigBuffer>
while(token != NULL)
{
token = strtok(NULL, delimiter);
sprintf(bigBuffer[++count], "%s", token);
}
//for(i = 0; i < count; i++)
//printf("i = %d : %s\n", i, bigBuffer[i]);
for(i = 0; i< 25; i++)
{
free(bigBuffer[i]);
}
} //end split()
You aren't checking for NULL from the return of strtok on the last iteration of the loop ... so strtok can return NULL, yet you still pass the NULL value in the token pointer to sprintf.
Change your while-loop to the following:
while(token = strtok(NULL, delimiter)) sprintf(bigBuffer[++count], "%s", token);
That way you can never pass a NULL pointer to strtok because the while-loop NULL-pointer check will enforce that token always has a valid value when sprintf is called with it as an argument.
You should ask gdb for a full traceback of where your program crashed. The fact that you don't know precisely where it crashed means you didn't ask it for a full traceback, which is important.

Resources