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?
Related
I'm fairly new to C and I'm trying to work out dynamic memory allocation for reading from a file. At least I think that's what I'm doing.
Anyway, this code works:
int readfromfile(FILE *filepointer)
{
size_t size = 2;
char *str = (char *) malloc(sizeof(char));
int character = 0;
size_t counter = 0;
while((character = fgetc(filepointer)) != EOF)
{
str = (char *) realloc(str, size);
str[counter] = (char) character;
size ++;
counter++;
}
str[counter] = '\0';
printf("+%s+", str);
free(str);
return 0;
}
And this code does not:
int main()
{
char *str = (char *) malloc(sizeof(char));
...
readfromfile(ifpointer, &str);
}
int readfromfile(FILE *filepointer, char **str)
{
size_t size = 2;
int character = 0;
size_t counter = 0;
while((character = fgetc(filepointer)) != EOF)
{
*str = (char *) realloc(*str, size);
*str[counter] = (char) character;
size ++;
counter++;
}
str[counter] = '\0';
printf("+%s+", *str);
free(str);
return 0;
}
I cannot understand why because as far as I understand I'm sending a pointer to the location of the char array to the function and accessing the data everytime. The compilers shows no error messages, it just loops through once and on the second loop crashes after the realloc every time. The character assigned to the first value is garbage too.
I have spent an age trying to get this to worked and done a lot of research so I apologise if I've missed a solution but I'm truly stuck at this point.
You get a crash because
*str[counter] = (char) character;
is the same as
*(str[counter]) = (char) character;
as opposed to
(*str)[counter] = (char) character;
which is actually what you wanted. Read Operator Precedence on Wikipedia. You'll find that [] has more precedence than the * (dereference operator).
Also, the cast here, as well as in the calls to realloc and malloc, is unnecessary. Don't forget to check the return value of realloc, malloc etc to see if they were successful in allocating memory.
Now, you have another problem: free(str); in the second code should be free(*str);. Note that after *str has been freed from the function, you aren't supposed to read or write into this memory location from main as it has now become invalid for you to tamper with.
in your int readfromfile(FILE *filepointer, char **str) the parameter char **str is actually the same as char *str[], which means **str is expecting an array of char pointers. however you're passing to it char *str which is just an array of char
when you use readfromfile(...) you should do it this way (something like...):
char *str[2] = {"some char array", "another char array"};
readfromfile(ifpointer, str);
or:
char *a = "this char array";
char **str = &a[0];
readfromfile(ifpointer, str);
you'll get the idea...
There are a lot of find/replace functions available on the internet, but i can't find why this is not working...( my own solution )
Here is what i tried
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* strrpl(char *str, char* find, char *replace)
{
int i;
char *pt = strstr(str, find), *firstStr;
firstStr = (char* )malloc(100 * sizeof(char));
// copy just until i find what i need to replace
// i tried to specify the length of firstStr just with pt - str
strncpy(firstStr, str, strlen(str) - strlen(pt));
strcat(firstStr, replace);
strcat(firstStr, pt + strlen(find));
for(i = 0; i < strlen(firstStr); i++)
str[i] = firstStr[i];
return str;
}
int main()
{
char *s, *s1, *s2;
s = (char* )malloc(100 * sizeof(char));
s1 = (char* )malloc(100 * sizeof(char));
s2 = (char* )malloc(100 * sizeof(char));
scanf("%s", s1);
scanf("%s", s2);
scanf("%s", s);
printf("%s", strrpl(s, s1, s2));
return 0;
}
The compilation gives me the error "segmentation fault" but i can't figure what memmory is he trying to alloc and he can't. I overrided a memory block or something? Please help :)
Thanks
I overrided a memory block or something?
You have:
A potential buffer overflow when you allocate firstStr. Who says the result will be less than 100 characters?
Another potential buffer overflow when you copy the answer back to the input string. Who says it will fit?
A potential buffer overflow each time you use scanf.
A memory leak each time you call malloc.
An inefficient implementation of strcpy just before return str;.
A crash (formally, undefined behaviour) when the input string does not contain the replacement string. strstr returns NULL when there is no match and you never check for it.
A potential issue with strncpy which leaves your string not NUL-terminated if there's not enough space for NUL.
Here is the immediate problem: when strstr returns NULL, your code does not pay attention. Add this line:
char *pt = strstr(str, find), *firstStr;
if (!pt) return str;
Another problem is that the call of strncpy is incorrect:
strncpy(firstStr, str, strlen(str) - strlen(pt));
it will leave firstStr unterminated, because str is longer than the substring being copied. The subsequent call
strcat(firstStr, replace);
will operate on a string that is not null-terminated, causing undefined behavior.
"Shotgun" approach to fixing it would be to use calloc instead of malloc to put zeros into firstStr. A more precise approach would be placing '\0' at the end of the copied substring.
With these fixes in place, your code runs OK (demo). However, there are several issues that need to be addressed:
You do not free any of the resources that you allocate dynamically - this results in memory leaks.
You do not compute how much memory to allocate - If a 5-character string is replaced for a 100-character string in a 100-character string, you overrun the temporary buffer.
You are using strncpy incorrectly - the function is intended for fixed-length strings. Use memcpy instead.
You are using strcat instead of memcpy or strcpy - this is inefficient.
You have not checked for the return value of strstr.
Try the below code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* strrpl(char *str, char* find, char *replace)
{
int i;
char *pt = strstr(str, find);
char *firstStr;
if(pt == NULL){
printf("cannot find string \n");
return NULL;
}
firstStr = (char* )malloc(100 * sizeof(char));
// copy just until i find what i need to replace
// i tried to specify the length of firstStr just with pt - str
strncpy(firstStr, str, strlen(str) - strlen(pt));
strcat(firstStr, replace);
strcat(firstStr, pt + strlen(find));
for(i = 0; i < strlen(firstStr); i++)
str[i] = firstStr[i];
return str;
}
int main()
{
char *s, *s1, *s2, *s3;
s = (char* )malloc(100 * sizeof(char));
s1 = (char* )malloc(100 * sizeof(char));
s2 = (char* )malloc(100 * sizeof(char));
s3 = (char* )malloc(100 * sizeof(char));
scanf("%s", s);//input string
scanf("%s", s1);//string to find
scanf("%s", s2);//string to replace
s3 = strrpl(s, s1, s2);
if(s3 != NULL)
printf("%s \n",s3);
return 0;
}
I am trying to put all the lines of a file in a char **.
My function is very simple:
the only parameter is a pointer to a char array, which containts the file.
I first caculate the number of lines to allocate my char **.
Once is it allocated, I use strtok_r to parse file. and then Segfault.
I wanted to know if it was possible to do that with this way?
char **getlines(char *file)
{
int i = 0;
int nblines = 0;
while (file[i] != '\0')
{
if (file[i] == '\n')
nblines++;
i++;
}
char **array = malloc(sizeof(char*) * nblines);
char *saveptr;
if (nblines == 0)
return NULL;
int a = 0;
char *c = strtok_r(file, "\n", &saveptr);
while (c)
{
array[a] = strtok_r(NULL, "\n", &saveptr);
a++;
}
return array;
}
Should be:
char **array = malloc(sizeof(char*) * nblines);
which allocates an array of pointers to your lines.
It's confusing to speak about a file while you're actually having a char* string.
Then your while(c) loop does not end because you're not updating c in it. I leave that to you to fix.
Also, you have a memory leak with return NULL;. Put that check above array's malloc().
Sure you need the re-entrant version of strtok()?
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;
}
I need to split a char array into CSV's. Actually we can do the reverse of it using strtok() like:
#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;
}
But in my case, there's an char array suppose char bits[1024]="abcdefghijklmn". I need to get the output as a,b,c,d,e,f,g,h,i,j,k,m,n.
Is there any function or library to do this i.e. in terms of raw meaning, for every character it has to put a comma.
Just iterate over the string until you hit the end-of-string '\0' character. Or use the length of the data in the array (which may be smaller than the array size) and use a simple for loop.
This works for a null terminated string. But it will leave a dangling comma at the end.
void tokenise(char *s, char *d)
{
while(*d++ = *s++) *d++ = ',';
}
If you know the length of the string already, you can pass that through. This will not leave a dangling comma.
void tokenise(char *s, char *d, int length)
{
int i = 0;
while((*d++ = *s++) && ((i++)<(length-1))) *d++ = ',';
}
In both examples, s is a pointer to the source string and d points to the output tokenised string. It is up to the calling code to ensure the buffer d points to is sufficiently large.
you can use this simple function from old basic :
// ............................................................. string word at
char * word_at(char *tString, int upTo, char *dilim) {
int wcount;
char *rString, *temp;
temp= (char *) malloc(sizeof(char) * (strlen(tString)+1));
strcpy(temp, tString);
rString= strtok(temp, dilim);
wcount=1;
while (rString != NULL){
if (wcount==upTo) {
return rString;
}
rString= strtok(NULL, dilim);
wcount++;
}
return tString ;
}
parameter : string , index and character delimiter
return : word : ( char *)
If you find easy to implement it, then this could help you to start
char* split_all( char arr[], char ch )
{
char *new, *ptr;
new = ptr = calloc( 1, 2*strlen( arr ) ); // FIXME : Error checks
for( ; *(arr + 1) ; new++, arr++ )
{
*new = *arr;
new++;
*new = ch;
}
*new = *arr;
return ptr;
}
You can re-use, optimize this for your requirement. Its a quick and dirty solution, feel free to fix it..