So i am trying to read lines and then split them in two with strtok . So if i would read "nice dog" it will first print what i read and then will print using the strtok commands "nice" and "dog" on the next line . But after second input i got Segmentation fault .Also , what does free(buf) do ? I've seen that the error is at this line : "strcpy(name, strtok(NULL, " "));" This is the code :
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *buf;
char command[32];
char name[32];
while((buf = readline("\n"))!=NULL)
{
if (strcmp(buf,"exit")==0)
break;
printf("%s\n",buf);
strcpy(command, strtok(buf, " "));
printf("%s\n", command);
strcpy(name, strtok(NULL, " "));
printf("%s\n", name);
if(buf[0]!=NULL)
add_history(buf);
}
free(buf);
return 0;
}
You must check the result of strtok if it's NULL meaning that no tokens where found you will get segmentation fault
char *pointer;
pointer = strtok(buf, " ");
if (pointer != NULL)
strcpy(command, pointer);
also, readline allocates new memory on every call so you should free inside the while loop.
Fix it this way
#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
int main()
{
char *buf;
char command[32];
char name[32];
while((buf = readline("\n"))!=NULL)
{
char *pointer;
if (strcmp(buf,"exit")==0)
break;
printf("%s\n",buf);
pointer = strtok(buf, " ");
if (pointer != NULL)
{
strcpy(command, pointer);
/* Don't print poitner otherwise since it is unintialized */
printf("%s\n", pointer);
}
/* subsequent calls to strtok must have first argument NULL */
pointer = strtok(NULL, " ");
if (pointer != NULL)
{
strcpy(name, pointer);
printf("%s\n", pointer);
}
if (buf != NULL) // this is never FALSE because of the while condition
add_history(buf);
free(buf);
}
return 0;
}
you also have to make sure that command and name will be big enough to fit the resulting stirng.
Related
I want to convert a string to an array of strings and I get an error
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int count = 0;
char *str = argv[1];
char *token, *last;
char **arr_str = calloc(9999, sizeof(char*));
token = strtok_r(str, " ,", &last);
arr_str[count] = strcpy(calloc(strlen(token), sizeof(char)), token);
while (token != NULL) {
count++;
token = strtok_r(NULL, " ", &last);
arr_str[count] = strcpy(calloc(strlen(token), sizeof(char)), token);
printf("%s", arr_str[count - 1]);
}
printf("------------");
while(arr_str[count])
printf("%s", arr_str[count--]);
exit (0);
}
how to allocate memory for a string and make a pointer to it from an array?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
/* always check argument count */
if(argc < 2) {
printf("Not enough arguments given\n");
return 1;
}
int count = 0;
char *str = malloc(strlen(argv[1] + 5));
memcpy(str, argv[1], strlen(argv[1]));
char *token, *last;
char **arr_str = calloc(9999, sizeof(char*));
token = strtok_r(str, " ,", &last);
while ((token = strtok_r(NULL, " ", &last)) != NULL) {
count++;
/* sizeof(char) is always 1 and is redundant unless you are on
a obscure platform that it returns other than 1
which shouldnt exist in modern world
*/
arr_str[count] = malloc(strlen(token) + 1);
strcpy(arr_str[count], token);
}
printf("------------");
while(arr_str[count])
printf("%s", arr_str[count--]);
exit (0);
}
strtok is destructive meaning it edits strings it encounters, it tried to edit argv which resulted in a segmentation error.
I also edited code to follow better practices and edited formatting.
You need memory for elements of the arr_str.
calloc(9999) while not great if this not going to end up in a serious application it's not a issue.
sizeof(char) should always return 1 on a normal modern system unless you are on extremely obscure system
Use puts(char* s) if you don't need string formatting.
You should do input validation.
I created a function to split a string with comma.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
char splitted_line[8][50];
void split(char *line){
printf("line 9\n");
char *part = strtok(line, ",");
printf("line 11\n");
for(int i=1; i<8; i++){
strcpy(splitted_line[i], part);
printf("%s\n", splitted_line[i]);
part = strtok(NULL, ",");
}
}
int main(){
char *line = "123,456,789";
split(line);
return 0;
}
but the result after running is :
line 9
Segmentation fault (core dumped)
it seems the problem is in char *part = strtok(line, ","); but I don't know what's that.
strtok() will modify passed original string directly.
You must not modify string literals.
char *line = "123,456,789";
should be modifyable array
char line[] = "123,456,789";
Also don't forget to check if part is not NULL before doing strcpy(splitted_line[i], part);.
I had this working before, but I was using pointers. getenv() keeps crashing so I copied the results using sprintf(). Now I want to deliminate with : and print only the first occurrence. Please help!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main(void) {
char buf[999];
const char *token;
// HTTP_PROXY == 8.8.8.8:8888, end result should print 8.8.8.8
sprintf(buf, "%s", getenv("HTTP_PROXY"));
*token = strsep(&buf, ":");
printf("New result: %s\n", token);
}
Since strsep wants a pointer to pointer, you must pass a pointer to pointer, not a pointer to array. This is not the same thing; make a pointer, and assign it buf. Pass a pointer to that new pointer to strsep to fix the first problem.
The second problem is that since strsep returns a pointer, you need to assign it to token, not to *token:
char buf[999];
const char *token;
// HTTP_PROXY == 8.8.8.8:8888, end result should print 8.8.8.8
sprintf(buf, "%s", getenv("HTTP_PROXY"));
char *ptr = buf; // Since ptr, is a pointer...
token = strsep(&ptr, ":"); // ...you can pass a pointer to pointer
printf("New result: %s\n", token);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char const *http_proxy = getenv("HTTP_PROXY");
if (http_proxy == NULL) {
fprintf(stderr, "HTTP_PROXY not set: default 8.8.8.8:8888");
http_proxy = "8.8.8.8:8888";
}
char *cpy = strdup(http_proxy);
char *token = strtok(cpy, ":");
if (token == NULL) {
fprintf(stderr, "wrong format");
return 1;
}
do {
printf("Token: %s\n", token);
} while ((token = strtok(NULL, ":")) != NULL);
free(cpy);
}
I am trying to process a character string in order to change something in a file. I read from a file a character string which contains a command and an argument, separated by a space character. I separated this array in tokens.
Now I want to pass the second token, which is the argument to a function. My problem is that when I run my program, the screen freezes and nothing happens. Here is my separating way and the call to the function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void create_file(char *argument)
{
//some code goes here
}
int main()
{
int i = -1;
char *token[5];
char command[20];
const char delim[1] = " ";
FILE *fin;
fin = fopen("mbr.op", "r");
while(fscanf(fin, "%[^\n]", command) == 1)
{
i = -1;
token[++i] = strtok(command, delim);
while(token[i] != NULL)
token[++i] = strtok(NULL, delim);
if(strcmp(token[0], "CREATE_FILE") == 0)
create_file(token[1]);
}
fclose(fin);
return 0;
}
You have a few errors, first command[20] is an uninitialised string and that will cause undefined behaviour. Second, you failed to check the first arg as well as the second, so I added a test where commented. Also, the strings are not long enough so I removed the length. Lastly I test for a NULL pointer passed to the function.
Edit code was added to the question to show that command[20] was initialised, but it is still too short to take the command and a reasonable file name (thanks to #ameyCU).
#include <stdio.h>
#include <string.h>
void create_file(char *argument)
{
if(argument == NULL)
printf("NULL pointer\n");
else
printf("Arg: %s\n", argument);
}
int main(void)
{
int i = -1;
char *token[5];
char command[] = "CREATE_FILE myfile.txt";
const char delim[] = " ";
token[++i] = strtok(command, delim);
while(token[i] != NULL)
token[++i] = strtok(NULL, delim);
if(token[0] != NULL && strcmp(token[0], "CREATE_FILE") == 0) // added test
create_file(token[1]);
return 0;
}
Program output
Arg: myfile.txt
The first error is present in array definition:
const char delim[1] = " ";
In C "" is a string - an array of characters delimited by '\0'. This means that what stands to the right of "=" is a string of two chars:
// ' ' + '\0'
//0x20 0x00
Therefore this should be an array of two chars:
const char delim[2] = " ";
or
const char delim[] = " ";
Or rather, how does strtok produce the string to which it's return value points? Does it allocate memory dynamically? I am asking because I am not sure if I need to free the token in the following code:
The STANDARD_INPUT variables is for exit procedure in case I run out of memory for allocation and the string is the tested subject.
int ValidTotal(STANDARD_INPUT, char *str)
{
char *cutout = NULL, *temp, delim = '#';
int i = 0; //Checks the number of ladders in a string, 3 is the required number
temp = (char*)calloc(strlen(str),sizeof(char));
if(NULL == temp)
Pexit(STANDARD_C); //Exit function, frees the memory given in STANDARD_INPUT(STANDARD_C is defined as the names given in STANDARD_INPUT)
strcpy(temp,str);//Do not want to touch the actual string, so copying it
cutout = strtok(temp,&delim);//Here is the lynchpin -
while(NULL != cutout)
{
if(cutout[strlen(cutout) - 1] == '_')
cutout[strlen(cutout) - 1] = '\0'; \\cutout the _ at the end of a token
if(Valid(cutout,i++) == INVALID) //Checks validity for substring, INVALID is -1
return INVALID;
cutout = strtok(NULL,&delim);
strcpy(cutout,cutout + 1); //cutout the _ at the beginning of a token
}
free(temp);
return VALID; // VALID is 1
}
strtok manipulates the string you pass in and returns a pointer to it,
so no memory is allocated.
Please consider using strsep or at least strtok_r to save you some headaches later.
The first parameter to the strtok(...) function is YOUR string:
str
C string to truncate. Notice that this string is modified by
being broken into smaller strings (tokens). Alternativelly, a null
pointer may be specified, in which case the function continues
scanning where a previous successful call to the function ended.
It puts '\0' characters into YOUR string and returns them as terminated strings. Yes, it mangles your original string. If you need it later, make a copy.
Further, it should not be a constant string (e.g. char* myStr = "constant string";). See here.
It could be allocated locally or by malloc/calloc.
If you allocated it locally on the stack (e.g. char myStr[100];), you don't have to free it.
If you allocated it by malloc (e.g. char* myStr = malloc(100*sizeof(char));), you need to free it.
Some example code:
#include <string.h>
#include <stdio.h>
int main()
{
const char str[80] = "This is an example string.";
const char s[2] = " ";
char *token;
/* get the first token */
token = strtok(str, s);
/* walk through other tokens */
while( token != NULL )
{
printf( " %s\n", token );
token = strtok(NULL, s);
}
return(0);
}
NOTE: This example shows how you iterate through the string...since your original string was mangled, strtok(...) remembers where you were last time and keeps working through the string.
According to the docs:
Return Value
A pointer to the last token found in string.
Since the return pointer just points to one of the bytes in your input string where the token starts, whether you need to free depends on whether you allocated the input string or not.
As others mentioned, strtok uses its first parameter, your input string, as the memory buffer. It doesn't allocate anything. It's stateful and non-thread safe; if strtok's first argument is null, it reuses the previously-provided buffer. During a call, strtok destroys the string, adding nulls into it and returning pointers to the tokens.
Here's an example:
#include <stdio.h>
#include <string.h>
int main() {
char s[] = "foo;bar;baz";
char *foo = strtok(s, ";");
char *bar = strtok(NULL, ";");
char *baz = strtok(NULL, ";");
printf("%s %s %s\n", foo, bar, baz); // => foo bar baz
printf("original: %s\n", s); // => original: foo
printf("%ssame memory loc\n", s == foo ? "" : "not "); // => same memory loc
return 0;
}
s started out as foo;bar;baz\0. Three calls to strtok turned it into foo\0bar\0baz\0. s is basically the same as the first chunk, foo.
Valgrind:
==89== HEAP SUMMARY:
==89== in use at exit: 0 bytes in 0 blocks
==89== total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated
==89==
==89== All heap blocks were freed -- no leaks are possible
While the code below doesn't fix all of the problems with strtok, it might help get you moving in a pinch, preserving the original string with strdup:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
const char s[] = "foo;bar_baz";
const char delims[] = ";_";
char *cpy = strdup(s);
char *foo = strtok(cpy, delims);
char *bar = strtok(NULL, delims);
char *baz = strtok(NULL, delims);
printf("%s %s %s\n", foo, bar, baz); // => foo bar baz
printf("original: %s\n", s); // => original: foo;bar_baz
printf("%ssame memory loc\n", s == foo ? "" : "not "); // => not same memory loc
free(cpy);
return 0;
}
Or a more full-fledged example (still not thread safe):
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void must(
bool predicate,
const char *msg,
const char *file,
const unsigned int line
) {
if (!predicate) {
fprintf(stderr, "%s:%d: %s\n", file, line, msg);
exit(1);
}
}
size_t split(
char ***tokens,
const size_t len,
const char *s,
const char *delims
) {
char temp[len+1];
temp[0] = '\0';
strcpy(temp, s);
*tokens = malloc(sizeof(**tokens) * 1);
must(*tokens, "malloc failed", __FILE__, __LINE__);
size_t chunks = 0;
for (;;) {
char *p = strtok(chunks == 0 ? temp : NULL, delims);
if (!p) {
break;
}
size_t sz = sizeof(**tokens) * (chunks + 1);
*tokens = realloc(*tokens, sz);
must(*tokens, "realloc failed", __FILE__, __LINE__);
(*tokens)[chunks++] = strdup(p);
}
return chunks;
}
int main() {
const char s[] = "foo;;bar_baz";
char **tokens;
size_t len = split(&tokens, strlen(s), s, ";_");
for (size_t i = 0; i < len; i++) {
printf("%s ", tokens[i]);
free(tokens[i]);
}
puts("");
free(tokens);
return 0;
}