Segmentation Fault using strtok() in C [duplicate] - c

This question already has answers here:
strtok segmentation fault
(8 answers)
Closed 9 years ago.
I get segmentation fault with the following code using strtok. Am I using strtok correctly?
int main()
{
dummy("90:90");
return 0;
}
int dummy(char *str)
{
char *mm, *hh;
int len = strlen(str), result;
if (len <= 0 || len > 5)
{
return 0;
}
hh = strtok(str, ":");
while(hh){
printf("%s", hh);
hh = strtok(NULL, ":");
}
return result;
}

strtok modified the content of its argument, so you can't pass a string literal. Change it to:
int main()
{
char str[] = "90:90";
dummy(str);
return 0;
}

you can not use strtok() with a constant string. And that what you did in your code.
Because the strtok() edit the string and the constant strings are a read only strings.
To fix your problem, Duplicate your string in a dynamic allocated memory (read-write memory) in this way:
int dummy(char *str)
{
char *mm, *hh;
int len = strlen(str), result;
if (len <= 0 || len > 5)
{
return 0;
}
char *buf = strdup(str); // Modif here
hh = strtok(buf, ":"); // Modif here
while(hh){
printf("%s", hh);
hh = strtok(NULL, ":");
}
free(buf); // Modif here
return result;
}

When function strtok is called with the first argument being a string which is not NULL, it changes the contents of that string, so that in the following calls (with NULL) it will be able to fetch the next token.
You, however, are passing a constant string which resides in the (read-only) code-section of your program. So during run-time, the CPU attempts to write into a read-only memory section, leading to an illegal memory access.
In short, you need to declare the string as a local array in the stack of function main:
int main()
{
char str[] = "90:90";
dummy(str);
return 0;
}

Related

strsep() causing Segmentation fault

I am having a problem with my program in which I am getting a segmentation fault from strsep() which was gotten from GDB and has the error message
Program received signal SIGSEGV, Segmentation fault.
0x00002aaaaad64550 in strsep () from /lib64/libc.so.6
My code is as follows:
int split(char *string, char *commands, char *character) {
char **sp = &string;
char *temp;
temp = strdup(string);
sp = &temp;
for (int i = 0; i < 100; i++) {
commands[i] = strsep(sp, character);
if (commands[i] == '\0') {
return 0;
}
if (strcasecmp(commands[i], "") == 0) {
i--;
}
printf("%d", i);
}
return 0;
}
Any help would be greatly appreciated as I have spent hours trying to solve this problem
The arguments for the function are ("Hello World", "#", "&")
EDIT
So I have managed to get rid of the segment fault by changing the code to
int split(char* string, char* commands, char* character) {
for(int i = 0; i < 100; i++) {
commands[i] = strsep(&string, character);
if(commands[i] == '\0') {
return 0;
}
if(strcasecmp(&commands[i], "") == 0) {
i--;
}
}
return 0;
}
However now I have a new problem with commands returning a null array where every index is out of bounds.
EDIT 2
I should also clarify on what I am trying to do a bit so essentially commands is of type char* commands[100] and I want to pass it into the function when then modifies the original pointer array and store say `"Hello World"' into commands[0] then I want to modify this value outside the function.
Your usage of commands is inconsistent with the function prototype: the caller passes an array of 100 char*, commands should be a pointer to an array of char *, hence a type char **commands or char *commands[]. For the caller to determine the number of tokens stored into the array, you should either store a NULL pointer at the end or return this number or both.
Storing commands[i] = strsep(...) is incorrect as commands is defined as a char *, not a char **.
It is surprising you get a segmentation fault in strsep() because the arguments seem correct, unless character happens to be an invalid pointer.
Conversely you have undefined behavior most likely resulting in a segmentation fault in strcasecmp(commands[i], "") as commands[i] is a char value, not a valid pointer.
Here is a modified version:
// commands is assumed to point to an array of at least 100 pointers
// return the number of tokens or -1 is case of allocation failure
int split(const char *string, char *commands[], const char *separators) {
char *dup = strdup(string + strcspn(string, separators));
if (temp == NULL)
return -1;
char *temp = dup;
char **sp = &temp;
int i = 0;
while (i < 99) {
char *token = strsep(sp, separators);
if (token == NULL) // no more tokens
break;
if (*token == '\0') // ignore empty tokens
continue;
commands[i++] = token;
}
commands[i] = NULL;
if (i == 0) {
free(dup);
}
return i;
}
The memory allocated for the tokens can be freed by freeing the first pointer in the commands array. It might be simpler to duplicate these tokens so they an be freed in a more generic way.

Error "munmap_chunk(): invalid pointer" in C program

I've written the following C function to split a string in a delimiter and return the word number "num_words":
void split_string(char *string, char **result, char *delimiter, int num_words){
long unsigned int cont_len = strlen(string);
char line[cont_len];
strcpy(line, string);
int i = 0;
char *tmp;
char *p = strtok (line, delimiter);
while ((p != NULL) & (i <= num_words)){
if (i == num_words){
*result = strdup(p);
break;
}
p = strtok (NULL, delimiter);
i = i+1;
}
free(p);
}
and in main:
char *string = "hello whole world";
char *result;
char *delimiter = " ";
int num_words = 2;
split_string(string, &result, delimiter, num_words);
In this example, split_string would make result equal to "world". However, when I try to debug with gdb, I get a munmap_chunk(): invalid pointer error originated in the free(p) code line of the split_string function.
I know that strdup allocates memory, and that's why I was trying to free the p pointer. Where should I place this free? Should I only free(result) in the main instead? I've read answers on similar stackoverflow questions, but none could solve my problem...
You don't need to free the memory after strtok.
For further reading: Do I need to free the strtok resulting string?

String and String array Manipulation in c

I'm trying to write a string spliter function in C.It uses space as delimiter to split a given string in two or more. It more like the split funtion in Python.Here is the code:-
#include <stdio.h>
#include <string.h>
void slice_input (char *t,char **out)
{
char *x,temp[10];
int i,j;
x = t;
j=0;
i=0;
for (;*x!='\0';x++){
if (*x!=' '){
temp[i] = *x;
i++;
}else if(*x==' '){
out[j] = temp;
j++;i=0;
}
}
}
int main()
{
char *out[2];
char inp[] = "HEllo World ";
slice_input(inp,out);
printf("%s\n%s",out[0],out[1]);
//printf("%d",strlen(out[1]));
return 0;
}
Expeted Output:-
HEllo
World
but it is showing :-
World
World
Can you help please?
out[j] = temp;
where temp is a local variable. It will go out of scope as soon as your function terminates, thus out[j] will point to garbage, invoking Undefined Behavior when being accessed.
A simple fix would be to use a 2D array for out, and use strcpy() to copy the temp string to out[j], like this:
#include <stdio.h>
#include <string.h>
void slice_input(char *t, char out[2][10]) {
char *x, temp[10];
int i,j;
x = t;
j=0;
i=0;
for (;*x!='\0';x++) {
if (*x!=' ') {
temp[i] = *x;
i++;
} else if(*x==' ') {
strcpy(out[j], temp);
j++;
i=0;
}
}
}
int main()
{
char out[2][10];
char inp[] = "HEllo World ";
slice_input(inp,out);
printf("%s\n%s",out[0],out[1]);
return 0;
}
Output:
HEllo
World
http://www.cplusplus.com/reference/clibrary/cstring/strtok/
From the website:
char * strtok ( char * str, const char * delimiters ); On a first
call, the function expects a C string as argument for str, whose first
character is used as the starting location to scan for tokens. In
subsequent calls, the function expects a null pointer and uses the
position right after the end of last token as the new starting
location for scanning.
Once the terminating null character of str is found in a call to
strtok, all subsequent calls to this function (with a null pointer as
the first argument) return a null pointer.
Parameters
str C string to truncate. Notice that this string is modified by being
broken into smaller strings (tokens). Alternativelly [sic], a null
pointer may be specified, in which case the function continues
scanning where a previous successful call to the function ended.
delimiters C string containing the delimiter characters. These may
vary from one call to another. Return Value
A pointer to the last token found in string. A null pointer is
returned if there are no tokens left to retrieve.
Example
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
You can use this function to split string into tokens - there is no need to use some own functions. Your code looks like garbage, please format it.
Your source propably would look like this:
char *
strtok(s, delim)
char *s; /* string to search for tokens */
const char *delim; /* delimiting characters */
{
static char *lasts;
register int ch;
if (s == 0)
s = lasts;
do {
if ((ch = *s++) == '\0')
return 0;
} while (strchr(delim, ch));
--s;
lasts = s + strcspn(s, delim);
if (*lasts != 0)
*lasts++ = 0;
return s;
}

passing a char* as argument breaks program whereas char[] does not [duplicate]

This question already has answers here:
What is the difference between char s[] and char *s?
(14 answers)
Definitive List of Common Reasons for Segmentation Faults
(1 answer)
Closed 5 years ago.
I have the following code to split strings by tokens:
char **strToWordArray(char *str, const char *delimiter)
{
char **words;
int nwords = 1;
words = malloc(sizeof(*words) * (nwords + 1));
int w = 0;
int len = strlen(delimiter);
words[w++] = str;
while (*str)
{
if (strncmp(str, delimiter, len) == 0)
{
for (int i = 0; i < len; i++)
{
*(str++) = 0;
}
if (*str != 0) {
nwords++;
char **tmp = realloc(words, sizeof(*words) * (nwords + 1));
words = tmp;
words[w++] = str;
} else {
str--;
}
}
str++;
}
words[w] = NULL;
return words;
}
If I do this:
char str[] = "abc/def/foo/bar";
char **words=strToWordArray(str,"/");
then the program works just fine but if I do this:
char *str = "abc/def/foo/bar";
char **words=strToWordArray(str,"/");
then I get a segmentation fault.
Why is that? The program expects a char* as an argument then why does a char* argument crash the program?
Because the function contains:
*(str++) = 0;
which modifies the string that was passed to it. When you do:
char *str = "abc/def/foo/bar";
str points to a read-only string literal. See the section titled Attempting to modify a string literal in this question:
Definitive List of Common Reasons for Segmentation Faults

C split string function

I am trying to implement function to split strings, but i keep getting segmentation faults. I am working on Windows XP, and therefore i also had to implement strdup(), because Windows API doesn't provide it. Can anyone tell me what's wrong with the following piece of code.
char** strspl(char* str, char* del)
{
int size = 1;
for(int i = 0; i < strlen(str);) {
if(strncmp(str + i, del, strlen(del)) == 0) {
size++;
i += strlen(del);
}
else {
i++;
}
}
char** res = (char**)malloc(size * sizeof(char*));
res[0] = strdup(strtok(str, del));
for(int i = 0; res[i] != NULL; i++) {
res[i] = strdup(strtok(NULL, del));
}
return res;
}
char* strdup(char* str) {
char* res = (char*)malloc(strlen(str));
strncpy(res, str, sizeof(str));
return res;
}
EDIT: using a debugger i found out, that program crashes after following line:
res[0] = strdup(strtok(str,del));
Also, i fixed strdup(), but there is still no progress.
You're not counting the null terminator and you are copying the wrong number of bytes
char* strdup(char* str) {
char* res = (char*)malloc(strlen(str)); /* what about the null terminator? */
strncpy(res, str, sizeof(str)); /* sizeof(str)
** is the same as
** sizeof (char*) */
return res;
}
Your strdup() function is not correct. The sizeof(str) in there is the size of the str pointer (probably 4 or 8 bytes), not the length of the string. Use the library provided _strdup() instead.
malloc does not initialize the allocated memory to \0. Have you tried using calloc instead? I suspect the seg faults are due to the res[i] != NULL comparison.
There are many things wrong with this code, but the main flaw is trying to implement this function. It will only provide you with marginal benefit, if any.
Compare the following two code snippets:
/* Using strtok... */
char *tok = strtok(str, del);
while (tok != NULL) {
/* Do something with tok. */
tok = strtok(NULL, del);
}
-
/* Using your function... */
char **res = strspl(str, del, &size);
size_t i;
for (i = 0; i < size; i++) {
/* Do something with *(res + i). */
}

Resources