I got a segment fault error at the line with the comments that contains lots of equals signs below.
The function below str_spit, I wrote it because I want to split a string using a specific char, like a comma etc.
Please help.
int str_split(char *a_str, const char delim, char *** result)
{
int word_length = 0;
int cur_cursor = 0;
int last_cursor = -1;
int e_count = 0;
*result = (char **)malloc(6 * sizeof(char *));
char *char_element_pos = a_str;
while (*char_element_pos != '\0') {
if (*char_element_pos == delim) {
char *temp_word = malloc((word_length + 1) * sizeof(char));
int i = 0;
for (i = 0; i < word_length; i++) {
temp_word[i] = a_str[last_cursor + 1 + i];
}
temp_word[word_length] = '\0';
//
*result[e_count] = temp_word;//==============this line goes wrong :(
e_count++;
last_cursor = cur_cursor;
word_length = 0;
}
else {
word_length++;
}
cur_cursor++;
char_element_pos++;
}
char *temp_word = (char *) malloc((word_length + 1) * sizeof(char));
int i = 0;
for (i = 0; i < word_length; i++) {
temp_word[i] = a_str[last_cursor + 1 + i];
}
temp_word[word_length] = '\0';
*result[e_count] = temp_word;
return e_count + 1;
}
//this is my caller function====================
int teststr_split() {
char delim = ',';
char *testStr;
testStr = (char *) "abc,cde,fgh,klj,asdfasd,3234,adfk,ad9";
char **result;
int length = str_split(testStr, delim, &result);
if (length < 0) {
printf("allocate memroy failed ,error code is:%d", length);
exit(-1);
}
free(result);
return 0;
}
I think you mean
( *result )[e_count] = temp_word;//
instead of
*result[e_count] = temp_word;//
These two expressions are equivalent only when e_count is equal to 0.:)
[] has a higher precedence than *, so probably parentheses will solve THIS problem:
(*result)[e_count] = temp_word;
I didn't check for more problems in the code. Hint: strtok() might do your job just fine.
Related
I get a segfault the second time this statement runs:
chunks[i].argv[0] = malloc( strlen(token) * sizeof(char *) + 1 );
The code in context is:
/* TODO: modify str_split to do the copying of its input string if it needs to (e.g. if it uses strtok on it), and return a struct that has the number of "chunks" it split out and the list of chunks. */
struct str_list *list_split(char *a_str, const char a_delim) {
char **result = 0;
char **result2 = 0;
size_t count = 0;
char *tmp = a_str;
char *last_comma = 0;
size_t count2 = 0;
char *tmp2 = a_str;
char *last_space = 0;
char delim[2];
delim[0] = a_delim;
delim[1] = 0;
struct str_list *chunks = NULL;
/* Count how many elements will be extracted. */
while (*tmp) {
if (a_delim == *tmp) {
count++;
last_comma = tmp;
}
tmp++;
}
/* Add space for trailing token. */
count += last_comma < (a_str + strlen(a_str) - 1);
/* Add space for terminating null string so caller
knows where the list of returned strings ends. */
count++;
result = malloc(sizeof(char *) * count);
chunks = malloc(sizeof(chunks));
//chunks.size = malloc(sizeof(int));
// counter = (int) count + 1;
//chunks->size = counter;
if (result == NULL) {
printf("Error allocating memory!\n"); //print an error message
return chunks;; //return with failure
}
if (result) {
size_t idx = 0;
char *token = strtok(a_str, delim);
int i = 0;
while (token) {
assert(idx < count);
*(result + idx++) = strdup(token); /* memory leak! how to free() */;
token = strtok(0, delim);;
}
assert(idx == count - 1);
*(result + idx) = 0;
}
chunks->size = (int) count;
chunks->argv = alloc_argv((unsigned) chunks->size);
for (int i = 0; i < 2; i++) { //count is wrong
while (*tmp2) {
if (' ' == *tmp2) {
count2++;
last_space = tmp2;
}
tmp2++;
}
char* token = strtok(result[i], " ");
while (token) {
printf("token: %s\n", token);
printf("size: %d\n", chunks->size);
printf("result: %s\n", result[i]);
printf("i: %d\n", i);
chunks[i].argv[0] = malloc( strlen(token) * sizeof(char *) + 1 );
chunks[i].argv[0] = strdup(token);;
token = strtok(0, " ");
}
}
return chunks;
}
My debugger says nothing interesting. Can you see what is wrong and what should be done? The call to the above function is:
int run_cmd(const char *cmd) {
struct str_list *chunks = list_split(cmd, '|');
struct pipeline *pipe = alloc_pipeline(2); //size is the number of pipelines
for (int i = 0; i < 2; i++) {
printf("i %d", i);
for (int j = 0; j < 1; j++) {
pipe[i].data[j] = chunks[i].argv[j];
}
}
int status = execute_pipeline(pipe);
// free_pipeline(pipe);
// free_str_list(chunks);
return status;
}
The definition of my structs is
struct str_list {
char *name;
int size;
char **argv;
};
struct pipeline {
char *name;
int size;
char **data;
};
This line
chunks = malloc(sizeof(chunks));
That allocates the size of the chunks variable, which is a pointer and is usually only 4 or 8 bytes large (depending on if you're on a 32 or 64 bit system).
A str_list structure is larger than that, which means you will write out of bounds of allocated memory, leading to undefined behavior and most likely a crash.
You seem to be using two of this structure, judging by the loops, which means you need to allocate two full str_list structures, which is simplest done by e.g.
chunks = malloc(2 * sizeof *chunks);
I want to return nothing when the string is number
here is my code,
#include <string.h>
#include <ctype.h>
int num = 0;
char* findWord(char* subString) {
char* word = malloc(sizeof(char) * (strlen(subString) + 1));
int i = 0;
int Position = 0;
num = 0;
while (ispunct(subString[i]) != 0 || isspace(subString[i]) != 0) {
i++;
}
num = i;
while (ispunct(subString[i]) == 0 && isspace(subString[i]) == 0) {
word[Position] = subString[i];
i++;
Position++;
}
word[Position] = '\0';
return word;
}
char** wordList(const char* s) {
int len = strlen(s);
int i = 0;
char* Copyword = malloc(sizeof(char) * len);
strncpy(Copyword, s, len);
char** result = (char**) malloc(sizeof(char*) * (len + 1));
char* word = NULL;
word = findWord(Copyword);
char* wordEnd = Copyword;
while (*word != 0) {
result[i] = word;
wordEnd = wordEnd + strlen(word) + num;
word = findWord(wordEnd);
i++;
}
result[i] = '\0';
free(Copyword);
return result;
}
int main(void) {
char** words = wordList("1 23 456 789");
int i = 0;
while (words[i] != NULL) {
printf("%s\n", words[i]);
free(words[i]); // We're done with that word
i++;
}
free(words); // We're done with the list
return 0;
}
my code is ok when the string is sentence.
however, in this case, I want to print nothing(just like a space) when the string is number.
but what I go is
1
23
456
789
I expect to get
nothing shows here! just a space
For starters: You pass a non 0-terminated C-"string" (Copyword) to findWord() and in there call strlen() on it. This just doesn't crash your app by bad luck.
I need to replace a strings in some text. I found this function here at stackoverflow:
char *replace(const char *s, const char *old, const char *new)
{
char *ret;
int i, count = 0;
size_t newlen = strlen(new);
size_t oldlen = strlen(old);
for (i = 0; s[i] != '\0'; i++) {
if (strstr(&s[i], old) == &s[i]) {
count++;
i += oldlen - 1;
}
}
ret = malloc(i + count * (newlen - oldlen));
if (ret == NULL)
exit(EXIT_FAILURE);
i = 0;
while (*s) {
if (strstr(s, old) == s) {
strcpy(&ret[i], new);
i += newlen;
s += oldlen;
} else
ret[i++] = *s++;
}
ret[i] = '\0';
return ret;
}
This function works for me fine for single replacement. But i need to replace a whole array "str2rep" to "replacement". So what i'm trying to do(im just a beginner)
****
#define MAXTEXT 39016
int l;
int j;
char *newsms = NULL;
char text[MAXTEXT];
char *str2rep[] = {":q:",":n:"};
char *replacement[] = {"?","\n"};
strcpy((char *)text,(char *)argv[5]);
l = sizeof(str2rep) / sizeof(*str2rep);
for(j = 0; j < l; j++)
{
newsms = replace(text,(char *)str2rep[j],(char *)replacement[j]);
strcpy(text,newsms);
free(newsms);
}
textlen = strlen(text);
This code even works locally, If I build it from single file... But this is asterisk module, so when this is being executed, asterisk stops with:
* glibc detected * /usr/sbin/asterisk: double free or corruption (!prev): 0x00007fa720006310 *
Issues:
ret = malloc(i + count * (newlen - oldlen)); is too small. Need + 1.
Consider what happens with replace("", "", ""). If your SO ref is this, it is wrong too.
Questionable results mixing signed/unsigned. count is signed. newlen, oldlen are unsigned.
I think the original code works OK, but I do not like using the wrap-around nature of unsigned math when it can be avoided which is what happens when newlen < oldlen.
// i + count * (newlen - oldlen)
size_t newsize = i + 1; // + 1 for above reason
if (newlen > oldlen) newsize += count * (newlen - oldlen);
if (newlen < oldlen) newsize -= count * (oldlen - newlen);
ret = malloc(newsize);
Insure enough space. #hyde Various approaches available here.
// strcpy(text, newsms);
if (strlen(newsms) >= sizeof text) Handle_Error();
strcpy(text, newsms);
Minor
No need for casts
// newsms = replace(text, (char *) str2rep[j], (char *) replacement[j]);
newsms = replace(text, str2rep[j], replacement[j]);
Better to use size_t for i. A pedantic solution would also use size_t count.
// int i;
size_t i;
I will suggest something that to me looks a bit more clear as an alternative, in place of a proper dynamic string implementation. Exception handling is left as an exercise for the reader to add. :)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *appendn(char *to, char *from, int length)
{
return strncat(realloc(to, strlen(to) + length + 1), from, length);
}
char *replace(char *string, char *find, char *sub)
{
char *result = calloc(1, 1);
while (1)
{
char *found = strstr(string, find);
if (!found)
break;
result = appendn(result, string, found - string);
result = appendn(result, sub, strlen(sub));
string = found + strlen(find);
}
return appendn(result, string, strlen(string));
}
int main()
{
const char text[] = "some [1] with [2] to [3] with other [2]";
char *find[] = {"[1]", "[2]", "[3]", NULL};
char *sub[] = {"text", "words", "replace"};
char *result, *s;
int i;
result = malloc(sizeof(text));
(void) strcpy(result, text);
for (i = 0; find[i]; i ++)
{
s = replace(result, find[i], sub[i]);
free(result);
result = s;
}
(void) printf("%s\n", result);
free(result);
}
I want to write a function that processes a string that looks like this:
|1,2,3,4|(1->2),(2->3),(3->1)|
The result should be a breaking down of the string into these strings:
1
2
3
4
(1->2)
(2->3)
(3->2)
This is my code:
int processPart(char*** dest, char* from) //Processes a half at a time
{
int len = 0;
char* cutout = strtok(from, ",");
while(cutout)
{
(*dest) = (char**)realloc(dest, (len + 1) * sizeof(char*)); <<<<<<<
(*dest)[len] = (char*)calloc(strlen(cutout) + 1, sizeof(char));
memcpy((*dest)[len], cutout, strlen(cutout));
cutout = strtok(NULL, ",");
len++;
}
return len;
}
void processInput(char*** vertices, char*** edges, char* input, int* sizev, int* sizee)
{
int vlen = 0, elen = 0;
char* string = input + 1;
char* raw_vertices;
char* raw_edges;
string[strlen(string)] = '\0';
raw_vertices = strtok(string, "|");
raw_edges = strtok(NULL, "|");
*sizev = processPart(vertices, raw_vertices); //First the vertices
*sizee = processPart(edges, raw_edges); //Then the edges
}
int main()
{
char* in = stInput(); //input function
char** c = NULL, **b = NULL;
int a, d, i;
processInput(&c, &b, in, &a, &d);
for(i = 0; i < a; i++)
{
printf("%s\n", c[i]);
}
printf("++++++++++++++++");
for(i = 0; i < d; i++)
{
printf("%s\n", b[i]);
}
return 0;
}
However, I get a corruption of the heap at the line marked by <<<<<<<
Anyone knows what my mistake is?
In the erroneous line
(*dest) = (char**)realloc(dest, (len + 1) * sizeof(char*));
a * is missing before the dest argument. You could have spotted this easier if you hadn't cluttered the expression with the useless cast. I'd write
*dest = realloc(*dest, (len + 1) * sizeof**dest);
- that way we can see better the matching of first argument and left operand of the assignment.
running this function more then once will cause a Segmentation fault and i cannot figure out why. Im not looking for alternative ways to split a string.
SplitX will continue splitting for x ammount of delimiters (be it '|' or '\0') and return the x or the number of substrings it could make.
I should note i have just restarted coding in C after 3 years of easy JavaScript and PHP so i could be missing something obvious.
int splitX(char **array, char *string, int x) {
int y;
int z;
int index = 0;
int windex = 0;
for(y = 0; y < x; y++) {
z = index;
while(string[index] != '\0' && string[index] != '|') {
index++;
}
char **tempPtr = realloc(array, (y+1)*sizeof(char *));
if(tempPtr == NULL) {
free(array);
return -3;
}
array = tempPtr;
array[y] = malloc(sizeof(char) * (index - z + 1));
windex = 0;
for(; z < index; z++) {
array[y][windex] = string[z];
windex++;
}
array[y][windex] = '\0';
if(string[index] == '\0')
break;
index++;
}
return y+1;
}
int main() {
char **array;
int array_len = splitX(array, query, 2);
printf("%s %s %d\n", array[0], array[1], array_len);
while(array_len > 0) {
free(array[array_len-1]);
array_len--;
}
free(array);
array_len = splitX(array, "1|2\0", 2);
printf("%s %s %d\n", array[0], array[1], array_len);
while(array_len > 0) {
free(array[array_len-1]);
array_len--;
}
free(array);
}
char **array;
int array_len = splitX(array, query, 2);
This lets splitX() use the uninitialized array, which results in undefined behavior.
Furthermore, C has no pass-by-reference - when you write
array = tempPtr;
inside the function, that has no visible effect outside it.
Im not looking for alternative ways to split a string.
You should really be. Your current approach is at best non-idiomatic, but it also has some other mistakes (like returning y + 1 for some reason where y would do certainly, etc.).
You are also reinventing the wheel: for string and character searching, use strstr(), strchr() and strtok_r() from the C standard library; for duplicaitng a string, use strdup() instead of going through the string manually, etc., etc...
What else:
use size_t for sizes instead of int;
maintain const correctness by using const char * for input strings.
char **split(const char *s, size_t *sz)
{
char **r = NULL;
size_t n = 0, allocsz = 0;
const char *p = s, *t = p;
int end = 0;
do {
const char *tmp = strchr(p, '|');
if (tmp == NULL) {
p = p + strlen(p);
end = 1;
} else {
p = tmp;
}
if (++n > allocsz) {
if (allocsz == 0)
allocsz = 4;
else
allocsz <<= 1;
char **tmp = realloc(r, sizeof(*r) * allocsz);
if (!tmp) abort(); // or whatever, handle error
r = tmp;
}
r[n - 1] = malloc(p - t + 1);
memcpy(r[n - 1], t, p - t);
r[n - 1][p - t] = 0;
p++;
t = p;
} while (!end);
*sz = n;
return r;
}