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;
}
Related
I have been trying to figure out how to modify an array of char pointers but no matter what I do there appears to be no change below are the three arrays I'm trying to change including the call to the function I'm using.
char*cm1[5];
char*cm2[5];
char*cm3[5];
setupCommands(&cm1,commands,file,0);
setupCommands(&cm2,commands,file,1);
setupCommands(&cm3,commands,file,2);
The code below is the function itself.I was thinking that maybe it involves a double pointer but if I try *cmd to change the array I get a segmentation fault.
void setupCommands(char **cmd[], char* commands[],char file[],int index){
char str1[255];
strcpy(str1,commands[index]);
char newString [5][255];
int j = 0;
int ctr = 0;
int i;
//printf("str1 %s\n" ,str1);
for(i = 0; i <= strlen(str1); i++){
if(str1[i] == ' '|| str1[i] =='\0'){
newString[ctr][j] = '\0';
ctr++;//next row
j=0;// for next word, init index to 0
}else{
newString[ctr][j]=str1[i];
j++;
}
}
for(i = 0; i < ctr; i++){
//printf(" test2 %s \n", newString[i]);
cmd[i] = newString[i];
//printf(" test2 %d %s \n", i,cmd[i]);
}
//printf("index %d", i);
cmd[i]= file;
cmd[i + 1] = NULL;
//execvp(cmd[0],cmd);
//cmd
}
There are a few issues with your code:
you are trying to return references to the local 'char newString [5][255]' when the function exits. In simple worlds - never return anything locally allocated on the stack. This is the reason you are getting the segmentation fault.
char **cmd[] must be declared char *cmd[] - even though you will get a warning from the compiler assignment from incompatible pointer type, the code would run and execute correctly(essentially **cmd[] would do the same work as *cmd[], even though it's not of correct type) if you didn't return references to the local object;
Easy and simple optimization is just to remove the array str1 and directly operate on the array commands.
Apart from this simple optimization I have changed your code to overcome the segmentation fault, by allocating on the heap, instead on stack(will live until the program terminates) the multidimensional array, and I also calculate it's size so I will know how much memory to allocate. Now it's safe to return references to it.
Note that more optimizations could be made, but for the sake of the simplicity this is the bare minimal for this code to work.
int setupCommands(char *cmd[], char *commands[], char file[], int index)
{
int j = 0;
int ctr = 0;
int i = 0;
int rows = 0;
int cols = 0;
char **newString = NULL;
while(commands[index][i])
{
if (commands[index][i] == ' ')
{
++rows;
}
++i;
}
++rows;
cols = strlen(commands[index]) + 1;
newString = malloc(rows * sizeof(*newString));
if (newString == NULL)
{
return -1;
}
for (i = 0; i < rows; ++i)
{
newString[i] = malloc(cols * sizeof(*newString));
if (newString[i] == NULL)
{
return -1;
}
}
for(i = 0; i <= strlen(commands[index]); i++){
if(commands[index][i] == ' '|| commands[index][i] =='\0'){
newString[ctr][j] = '\0';
ctr++;//next row
j=0;// for next word, init index to 0
}else{
newString[ctr][j]=commands[index][i];
j++;
}
}
for(i = 0; i < ctr; i++){
cmd[i] = newString[i];
}
cmd[i]= file;
cmd[i + 1] = NULL;
return 0;
}
First of all - being the three stars pointer programmer is not good :)
You assign it with pointer to the local variable which is not longer available after the function return
But if you still want the three stars pointers:
char **cm1;
char **cm2;
char **cm3;
setupCommands(&cm1,commands,file,0);
setupCommands(&cm2,commands,file,1);
setupCommands(&cm3,commands,file,2);
#define MAXWORD 256
int setupCommands(char ***cmd, const char *commands,const char *file,int index){
char str1[255];
strcpy(str1,commands[index]);
int j = 0;
int ctr = 0;
int i;
//printf("str1 %s\n" ,str1);
*cmd = malloc(sizeof(char *));
**cmd = malloc(MAXWORD);
if(!*cmd || !**cmd)
{
/* do spmething if mallocs failed*/
return -1;
}
for(i = 0; i <= strlen(str1); i++){
if(str1[i] == ' '|| str1[i] =='\0'){
(*cmd)[ctr][j] = '\0';
ctr++;//next row
*cmd = realloc((ctr + 1) * sizeof(int));
(*cmd)[ctr] = malloc(MAXWORD);
if(!*cmd || !*cmd[ctr])
{
/* do spmething if mallocs failed*/
return -1;
}
j=0;// for next word, init index to 0
}else{
(*cmd)[ctr][j]=str1[i];
j++;
}
}
*cmd = realloc(sizeof(char *) * ctr + 2)
(*cmd)[ctr - 2] = malloc(MAX);
if(!*cmd || !*cmd[ctr - 2])
{
/* do spmething if mallocs failed*/
return -1;
}
strcpy((*cmd)[ctr - 2], file);
(*cmd)[ctr - 1] = NULL;
return 0;
//execvp(cmd[0],cmd);
//cmd
}
you can improve many things (for example do not realloc every time but in the larger chunks) and I did not change anything in your code logic.
i want to make a function that returns an array of doubles from a specific string.
i've tried multiple options and did not succeed
i have a given function createWeightsArray and i need to fill it.
the numofgrades will be also given which is helpful
the string will be something like: "30% 40% 50%" and i in need a double array {0.3,0.4,0.5}
this is my latest try:
double* createWeightsArray(char* str, int numOfGrades) {
double *gradesweight;
gradesweight = (double*)malloc(numOfGrades * sizeof(double));
int i = 0, n = 0;
while (*str != '\0') {
while (strchr("%", *str)) ++str;
if (*str == '\0') break;
*(gradesweight + n) = (atof(str) / 100);
n++;
str = strstr(str, "% ");
if (str == NULL) break;
*str = '\0';
++str;
}
return gradesweight;
any help will be apprciated
Check it out.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
double* str2double(char *string, int length)
{
int index = 0;
const char delimitor[2] = "% "; /* Delimintor, used the break the string */
char *token;
double *array = malloc(sizeof(double) * length);
if (array == NULL){
fprintf(stderr, "Failed to allocate memory \n");
return NULL;
}
/* get the first token */
token = strtok(string, delimitor);
/* walk through other tokens */
for( index=0; token != NULL && index < length ; index++)
{
array[index] = strtod(token, &token) / 100;
token = strtok(NULL, delimitor);
}
return array;
}
int main()
{
char str[] = "30% 40% 80% 60%";
double *ptr = str2double(str, 4);
if (ptr != NULL) {
for (int i = 0; i < 4; i++)
printf( "%f\n", ptr[i]);
}
return 0;
}
You can use strtoklike this
double* createWeightsArray(char* str1, int numOfGrades) {
double *gradesweight;
char *str =strdup(str1);
gradesweight = (double*)malloc(numOfGrades * sizeof(double));
int i = 0;
*gradesweight = atof(strtok(str,"%"))/100;
i++;
while (--numOfGrades) {
*(gradesweight+i) = atof(strtok(NULL,"%") )/100;
i++;
}
return gradesweight;
}
As you are certain that numOfGrades are provided so better check for zero value of numberOfGrades before calling this function.
I'm observing some really weird behavior regarding realloc .... I was wondering if y'all could help me.
I have an array of dynamically allocated char *'s called "frags". I also have a char * called "combination" which points to some string literal that represents a new fragment. I want to replace one of the fragments within "frags" with the contents of "combination." The way my project is structured, I am sending the frags array, index of to-be-replaced frag, and combination string into a function. Within this function I have:
printf("combination before realloc: %s\n", combination);
char *newString = (char *) realloc(frags[firstIndex], strlen(combination) + 1);
assert(newString != NULL);
printf("combination after realloc: %s\n", combination);
strcpy(newString, combination);
frags[firstIndex] = newString;
Oddly, the printf's do not print the same thing. The first printf yields "hellol" which is correct, but the next printf yields jibberish - something like "{?`?p??". Thus, the problem resides in the call to realloc. And I honestly have no idea what's going on. It seems the very call to realloc has messed with combination somehow, but I thought that if that could possibly happen then it would return NULL?
Please help me :(
Edit: Adding code
bool findMaxOverlap(char *first, char *second, char **combination, int *roundMax) {
// setup lng and shrt
char *lng, *shrt;
if (strlen(first) >= strlen(second)) { lng = first; shrt = second; }
else { lng = second; shrt = first; }
int shrtLen = strlen(shrt), lngLen = strlen(lng);
// check if lng contains shrt
if (strstr(lng, shrt) != NULL && shrtLen > *roundMax) {
*combination = lng;
*roundMax = shrtLen;
return true;
}
else // check if lng's tail ends contain part of shrt
{
int numChars = shrtLen - 1, max = 0, shrtOffset = 0, lngOffset = 0;
for (int i = 0; i < shrtLen && numChars > *roundMax && numChars > max; i++) {
numChars = shrtLen - 1 - i;
for (int j = 0; j < lngLen; j++) {
if (strncmp(shrt + i, lng + j, numChars) == 0) {
max = numChars;
shrtOffset = i;
lngOffset = j;
}
}
}
if (shrtOffset > lngOffset) {
// short first
char newFrag[lngLen + shrtOffset + 1];
strncpy(newFrag, shrt, shrtOffset);
strcat(newFrag, lng + shrtOffset);
*combination = newFrag;
*roundMax = numChars;
return true;
} else {
// lng first
char newFrag[lngLen + (shrtLen - numChars) + 1];
strcpy(newFrag, lng);
strcat(newFrag, shrt + numChars);
*combination = newFrag;
printf("combination in findmax is: %s\n", *combination);
*roundMax = numChars;
return true;
}
}
return false;
}
void mergeFrags(char *frags[], int index1, int index2, char *combination) {
int firstIndex, secondIndex;
if (index1 < index2) {
firstIndex = index1;
secondIndex = index2;
} else {
firstIndex = index2;
secondIndex = index1;
}
char temp[strlen(combination) + 1];
strcpy(temp, combination);
char *newString = (char *) realloc(frags[firstIndex], strlen(combination) + 1);
assert(newString != NULL);
strcpy(newString, temp);
frags[firstIndex] = newString;
free(frags[secondIndex]);
}
char *reassemble(char *frags[], int numFrags) {
if (numFrags > 1) {
char *combination;
int max, index1, index2, currNumFrags = numFrags;
for (int currentRound = 0; currentRound < numFrags - 1; currentRound++) {
max = index1 = index2 = 0, combination = NULL;
for (int i = 0; i < currNumFrags; i++) {
for (int j = i+1; j < currNumFrags; j++) {
//find max overlap of pair
if (findMaxOverlap(frags[i], frags[j], &combination, &max)) {
printf("round #: %d, combination: %s, max: %d\n", currentRound, combination, max);
index1 = i; index2 = j;
}
}
}
// merge
mergeFrags(frags, index1, index2, combination);
currNumFrags--;
}
}
return frags[0];
}
You said (in the comments above) that you were using strdup to allocate the data in combination, but what you're really doing is setting combination to point to data that's on the stack. After findMaxOverlap returns, you are now pointing at unallocated space on the stack, and this provides you with the undefined behavior you're seeing. When realloc is called, the area in the stack is reused, and the value of combination looks like garbage.
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.
I'm new in programming in C and I got 2 problems. I have two string, then I need to split them into words and find out if both strings contains same words. I will explain it with my code.
Input:
"He said he would do it."
"IT said: 'He would do it.'"
This two string are placed into two arrays. At first I need to parse words from others characters.
Call function:
char ** w1 = parse(s1, &len1);
Variable len counts number of rows (words).
Function parse:
char ** parse(char *w, int * i)
{
int j = 0, y, dupl = 0; //variables for cycles and duplicate flag
char d[] = " <>[]{}()/\"\\+-*=:;~!##$%^&_`'?,.|";
char* token = strtok(w, d);
unsigned len = strlen(token), x;
unsigned plen = len;
char ** f = (char**) malloc(len * sizeof (char*));
while (token != NULL)
{
len = strlen(token);
for (x = 0; x < len; x++)
{
token[x] = tolower(token[x]);
}
for (y = 0; y < *i; y++) //cycle for deleting duplicated words
{
if (equals(token, f[y]) == 1)
{
dupl = 1; break;
}
}
if (dupl == 1)
{
token = strtok(NULL, d);
dupl = 0;
continue;
}
if (len >= plen)
{
f = (char**) realloc(f, (len+1) * sizeof (char*));
plen = len;
}
else
f = (char**) realloc(f, (plen+1) * sizeof (char*));
f[j] = token;
token = strtok(NULL, d);
*i = *i + 1;
j++;
}
free(token);
return f;
}
Ok, now i have 2x 2Darrays, then just sort it (qsort(w1, len1, sizeof (char*), cmp);) and compare it:
for (i = 0; i < len2; i++)
if (equals(w1[i], w2[i]) == 0)
return 0;
Function equals:
int equals(char *w1, char *w2)
{
if (strcmp(w1, w2) == 0)
return 1;
return 0;
}
I know that all of this can be faster, but at first I need to solve my problem. This works for input which I wrote at the beginning, but when I type something long e.g.500 characters, my result is Aborted. I think that the problem is here:
f = (char**) realloc(f, (len+1) * sizeof (char*));
but dunno why.
Second thing is, that I can't free my arrays. This
void Clear (char ** w, int max)
{
int i;
for (i = 0; i < max; i++)
free(w[i]);
free(w);
}
gives me a segmentation fault.
Thanks for your time and I'm sorry for my bad english and bad programming skills.
It seems to have confused the word length and number of words in the parse function in your logic.
char ** f = (char**) malloc(len * sizeof (char*));
I think for example of len in portions of the above are as should be the number of words rather than characters.