Im trying to split a string according to the following rules:
words without "" around them should be treated as seperate strings
anything wiht "" around it should be treated as one string
However when i run it in valgrind i get invalid frees and invalid read size errors, but if i remove the two frees i get a memory leak. If anyone could point me in the right direction i would appreciate it
The code that calls split_string
char *param[5];
for(i = 0;i < 5;i++) {
param[i] = NULL;
}
char* user = getenv("LOGNAME");
char tid[9];
char* instring = (char*) malloc(201);
/
while((printf("%s %s >",user,gettime(tid)))&&(instring
=fgets(instring,201,stdin)) != NULL) {
int paramsize = split_string(param, instring);
The code that tries to free param
for(i = 0;i < 5;i++) {
if(param[i] != NULL) {
free(param[i]);
fprintf(stderr,"%d",i);
}
}
int split_string(char** param, char* string) {
int paramplace = 0; //hvor vi er i param
int tempplace = 0; //hvor i temp vi er
char* temp = malloc(201);
int command = 0;
int message = 0;
for(; (*string != '\0') && (*string != 10) && paramplace < 4; string++) {
if((*string == ' ') && (message == 0)) {
if(command == 1) {
temp[tempplace] = '\0';
param[paramplace++] = temp;
tempplace = 0;
command = 0;
}
}
else {
if(*string =='"') {
if(message == 0) message = 1;
else message = 0;
}
if(command == 0) {
free(temp);
temp = malloc(201);
}
command = 1;
if(*string != '"') {
temp[tempplace++] = *string;
}
}
}
if(command == 1) {
temp[tempplace] = '\0';
param[paramplace++] = temp;
}
param[paramplace] = NULL;
free(temp);
return paramplace;
}
As far as I can see, you want to put the split strings into param as an array of pointers (presumably making the caller responsible for freeing them). In the first branch of the if statement in your loop, you do so by assigning the current temp buffer to that place. However, once you start a new string (when comnmand == 0, you free that space, rendering the previous param entry pointer invalid.
Only free each pointer once. I wouldn't rule out other leaks in this code: I think you can simplify your state machine (and probably find other bugs as a result).
When you free the temp buffer you also free the param[] buffer, where your tokens are stored. On the other hand, if you don't call free(temp), which you shouldn't, it will be the responsibility of the caller of your function to call free(param[n]), when the tokens aren't needed.
Maybe you're not removing the right free()'s? The actual problem might be in the code that calls split_string. Can you show it?
It's hard to understand your code. I suggest you use sscanf instead.
You can use a format string like this:
"\"%[^\"]\"%n"
Read up on what it does.
I wrote an example:
if( sscanf( string, "\"%[^\"]\"%n", matchedstring, &bytesread ) )
{
handlestring( matchedstring );
string += bytesread;
}
else if( sscanf( string, "%s%n", matchedstring, &bytesread ) )
{
handlestring( matchedstring );
string += bytesread;
}
else
{
handleexception();
}
Untested. :)
Thanks to all the comments i found the answer.
The problem was that the first malloc before the for loop is superfluous as there will be another one before it starts to put temp into param and therefore there were no pointers to the first malloc so it was simply lost.
Related
I'm creating a program to execute user inputted bash commands using the execvp function. After executing each command, it should take another command and execute that one. For example:
bash$ ./prog ls -l
-rw-r--r--. 1 (info-placeholder) file1.txt
ls -l
-rw-r--r--. 1 (info-placeholder) file1.txt
For this, I need to be able to parse each of the user's input into a char**, since this is the execvp function: execvp(const char *file, char *const argv[]);
So, I created this function to parse the user's input and place it in a dynamically allocated char** called arg_list, where buff is the buffer the program read into and bytes is the number of bytes the read function read.
void parse_input(char **arg_list, char *buff, int bytes) {
char *word = malloc(128);
int num_spaces = 0;
for (int i = 0; i < bytes; i++) {
if (buff[i] == ' ') {
num_spaces++;
} // if
} // for
arg_list = malloc((num_spaces) * sizeof(char *));
for (int i = 0, j = 0; i < bytes; i++) {
if (buff[i] != ' ' && buff[i] != (char) 0) {
word[i] = buff[i];
} else {
word[i] = '\0';
arg_list[j] = word;
j++;
free(word);
word = malloc(128);
} // else
} // for
free(word);
} // parse_input
After testing ls -l as user input, it appears that word is not being reset after being added to arg_list. I'm not sure how else I could add the user inputted words into the list, and why word is not being reset.
Edit:
I now realize how many errors there were in my code, and there probably are still many more, sorry. To keep this short, I've tried to fix my code based on yall's corrections, but I still can't seem to get it to work. Here it is:
void pars_input(char ***arg_list, char *buff, int bytes) {
printf("Beginning to parse user input\n");
int num_spaces = 0;
bool is_white_space = true;
for (int i = 0; i < bytes; i++) {
if (is_white_space && !isspace(buff[i])) {
num_spaces++;
is_white_space = false;
} else if (!is_white_space && isspace(buff[i])) {
is_white_space = true;
} // else if
} // for
printf("Number of words: %d\n", num_spaces);
(*arg_list) = malloc((num_spaces + 1) * sizeof(char *));
is_white_space = true;
for (int i = 0, j = 0, k = 0; i < bytes; i++) {
if (is_white_space && !isspace(buff[j])) {
(*arg_list)[j][k] = '\0';
printf("Word added: %s\n", (*arg_list)[j]);
j++;
k = 0;
} // if
else if (!is_white_space && isspace(buff[i])) {
is_white_space = true;
(*arg_list)[j][k] = buff[i];
k++;
} // else if
} // for
} // parse_input
I cannot figure out how to add the word to the dynamically allocated arg_list without having a temporary word to which I add the chars from the buff.
The problems are numerous.
You don't want to free the memory to which word points. It's also being pointed by arg_list[ j ], which you're still using. Remove the first free(word);.
The last word doesn't isn't terminated by a space, so it doesn't get added to arg_list.
word[i] = buff[i]; is obviously wrong for any but the first the word. It's also wrong for the first word if the input starts with a space.
You allocate num_spaces elements, but there could be one more than that. For example, a b c has two spaces, but three words.
You don't handle leading spaces.
You don't handle multiple spaces in a row.
You only consider spaces as word separators, excluding tabs for example.
You take arg_list as an argument, but you replace its value without ever using it.
You don't return the list to the caller. Changing arg_list has no effect on the caller since C passes by value.
Returning arg_list to the caller isn't enough. The caller will also need some way of knowing how many elements are in the array. For example, this could be achieved by adding an additional element which is NULL, like exec* expects.
I am writing a simple Shell for school assignment and stuck with a segmentation problem. Initially, my shell parses the user input to remove whitespaces and endofline character, and seperate the words inside the input line to store them in a char **args array. I can seperate the words and can print them without any problem, but when storing the words into a char **args array, and if argument number is greater than 1 and is odd, I get a segmentation error.
I know the problem is absurd, but I stuck with it. Please help me.
This is my parser code and the problem occurs in it:
char **parseInput(char *input){
int idx = 0;
char **parsed = NULL;
int parsed_idx = 0;
while(input[idx]){
if(input[idx] == '\n'){
break;
}
else if(input[idx] == ' '){
idx++;
}
else{
char *word = (char*) malloc(sizeof(char*));
int widx = 0; // Word index
word[widx] = input[idx];
idx++;
widx++;
while(input[idx] && input[idx] != '\n' && input[idx] != ' '){
word = (char*)realloc(word, (widx+1)*sizeof(char*));
word[widx] = input[idx];
idx++;
widx++;
}
word = (char*)realloc(word, (widx+1)*sizeof(char*));
word[widx] = '\0';
printf("Word[%d] --> %s\n", parsed_idx, word);
if(parsed == NULL){
parsed = (char**) malloc(sizeof(char**));
parsed[parsed_idx] = word;
parsed_idx++;
}else{
parsed = (char**) realloc(parsed, (parsed_idx+1)*sizeof(char**));
parsed[parsed_idx] = word;
parsed_idx++;
}
}
}
int i = 0;
while(parsed[i] != NULL){
printf("Parsed[%d] --> %s\n", i, parsed[i]);
i++;
}
return parsed;
}
In your code you have the loop
while(parsed[i] != NULL) { ... }
The problem is that the code never sets any elements of parsed to be a NULL pointer.
That means the loop will go out of bounds, and you will have undefined behavior.
You need to explicitly set the last element of parsed to be a NULL pointer after you parsed the input:
while(input[idx]){
// ...
}
parsed[parsed_idx] = NULL;
On another couple of notes:
Don't assign back to the same pointer you pass to realloc. If realloc fails it will return a NULL pointer, but not free the old memory. If you assign back to the pointer you will loose it and have a memory leak. You also need to be able to handle this case where realloc fails.
A loop like
int i = 0;
while (parsed[i] != NULL)
{
// ...
i++;
}
is almost exactly the same as
for (int i = 0; parsed[i] != NULL; i++)
{
// ...
}
Please use a for loop instead, it's usually easier to read and follow. Also for a for loop the "index" variable (i in your code) will be in a separate scope, and not available outside of the loop. Tighter scope for variables leads to less possible problems.
In C you shouldn't really cast the result of malloc (or realloc) (or really any function returning void *). If you forget to #include <stdlib.h> it could lead to hard to diagnose problems.
Also, a beginner might find the -pedantic switch helpful on your call to the compiler. That switch would have pointed up most of the other suggestions made here. I personally am also a fan of -Wall, though many find it annoying instead of helpful.
Hi I read that I should call free() as soon as I could do that to free the memory but when I call free in this way my code stops working correctly. what's the problem?
I want to call free() in every iteration and when an error occurs.
int read_words(char *words[], int size, int max_str_len) {
int i, j;
char *ExtendedWord = NULL;
for (i = 0; i < size && size != -1; ++i) {
char tmp[1], ch, *word = tmp;
for (j = 0; j < max_str_len; ++j) {
if (scanf("%c", &ch) == EOF || ch == 'R') {
size = -1;
break;
}
if (ch == ' ')
break;
word[j] = ch;
ExtendedWord = malloc((i + 2) * sizeof(char));
if (ExtendedWord == NULL)
return -1;
strcpy(ExtendedWord, word);
word = ExtendedWord;
free(ExtendedWord);
}
word[j] = '\0';
words[i] = word;
}
return i;
}
strcpy(ExtendedWord,word);
strcpy() expects as 2nd parameter the address of the 1st character of a "C"-string, which in fact is a char-array with at least one element being equal to '\0'.
The memory word points to does not meet such requirements.
Due to this the infamous undefined behaviour is invoked, probably messing up the program's memory management, which in turn causes free() to fail.
There are multiple problems in your code:
you free the newly allocated block instead of the previous one.
you so not null terminate the string before passing it to strcpy
word should be initialized as NULL or to a block of allocated memory, not to point to a local array which you cannot pass to free().
you should reallocate the array before copying the new character at its end.
Here is a modified version:
int read_words(char *words[], int size, int max_str_len) {
int i, j;
for (i = 0; i < size; i++) {
char *word = malloc(1);
if (word == NULL)
return -1;
for (j = 0; j < max_str_len; ++j) {
int ch;
char *ExtendedWord;
if ((ch = getchar()) == EOF || ch == 'R') {
size = -1;
break;
}
if (ch == ' ' || c == '\n')
break;
/* reallocate array for one more character and a null terminator */
ExtendedWord = malloc(i + 2);
if (ExtendedWord == NULL)
return -1;
memcpy(ExtendedWord, word, i);
free(word);
word = ExtendedWord;
word[j] = ch;
}
if (size == -1) {
free(word);
break;
}
word[j] = '\0';
words[i] = word;
}
return i;
}
I Read that I should call free() as soon as I could do that to free the memory
That description is a little ambiguous. It is reasonable only if you interpret "as soon as I could do that" to mean the same as "as soon as I no longer need the allocated memory".
but when I call free in this way my code stops working correctly. what's the problem?
The problem with respect to free is that you free the memory before you are done with it. Subsequently attempting to access that memory produces undefined behavior.
There are other problems with the code, too, discussed in other answers, but this is how the free fits into the picture.
I want to call free in every iteration and when an error occurs.
Inasmuch as it appears that your function intends to provide pointers to the allocated memory to its caller via the words array, you must not free that memory anywhere within the scope of the function, because the caller (it must be presumed) intends to use it. Therefore the caller must assume the responsibility for freeing it. The function's documentation should clearly describe that responsibility.
Perhaps the confusion arises here:
word=ExtendedWord;
It is essential to understand that the assignment copies the pointer, not the space to which it points. Afterward, word points to the same (dynamically allocated) space that ExtendedWord does, so that freeing ExtendedWord invalidates both copies of the pointer.
I am little bit familiar to C but I have still much to learn and I have a little problem now. I am trying read some specific Variables (specific text) from txt file and store it in structure for which I allocated memory and then work with the data I obtained and saved in allocated structure and change variables values during runtime to get correct answer.
So far, I have done first part.. to allocate and read variables from file and then if necessary dynamically reallocate existing memory for every variable for which current memory (before reallocation) is small to be saved in it.
I declared structure varData, instantiated 2 times and allocated memory for one of them in MAIN func:
varData *dynamicData;
dynamicData = (varData*)malloc(sizeof(varData));
varData *tmp;
tmp = NULL;
Then, I have created a function loadVariablesToMemory in which I am reading file and identifiing variables in text and reallocating memory (for which current memory is not sufficient) for additional variables to be stored.
I run a debug and everything works fine when I am inside the function loadVariablesToMemory. Memory dynamicData is filled with variable names, but as soon as program leaves the function, memory is LOST or garbage is in it and I dont know why? As soon program jumps out from function all data in memory is LOST and garbage is in it.
typedef struct data {
char varName[10];
int value;
} varData;
#include "functions.h"
int main()
{
//ALLOCATING MEMORY
varData *dynamicData;// = malloc(sizeof(varData));
dynamicData = (varData*)malloc(sizeof(varData));
varData *tmp;// = NULL;
tmp = NULL;
//tmp = (varData*)realloc(dynamicData, sizeof(varData));
int numOfVars = loadVariablesToMemory("u02v1_input_03.txt", "r", dynamicData, tmp);
printf("%i \n", numOfVars);
for (int k = 0; k<=numOfVars-1; k++) {
printf("%s \n", (dynamicData+k)->varName);
}
return 0;
}
Function loadVariablesToMemory looks like this:
int loadVariablesToMemory(const char* fileName, const char* fileAccessMode, varData *dynamicData, varData *tmp) {
FILE *fSource = fopen(fileName, fileAccessMode);
char oneChar = '\0';
char buffer[10];
memset(buffer,'\0',10); //inicialization of buffer chars to \0
int i = 0;
int varOrNum = 0;
int numOfVars = 0;
bool match = false;
while (!feof(fSource)) {
oneChar = fgetc(fSource); //Load letter in file
if((oneChar == ' ') | (oneChar == '\n')) {
i = 0;
if((strcmp(buffer,"NOT") == 0) || (strcmp(buffer,"AND") == 0) || (strcmp(buffer,"OR") == 0) || (strcmp(buffer,"LSHIFT") == 0) || (strcmp(buffer,"RSHIFT") == 0) || (strcmp(buffer,"->") == 0)) {
memset(buffer,'\0',10);
}
else{
varOrNum = atoi(buffer); //returns (0) if varOrNum is variable (0)
if((varOrNum == 0) & (buffer[0] != '0'))
{ //if varOrNum is a variable (0)
for(int j = 0; j<=numOfVars; j++) { //control in memory for match of variable name
if(strcmp((dynamicData+j-1)->varName, buffer) == 0){
memset(buffer,'\0',10);
match = true; //match found
break;
}
else
match = false; //no match found
} //endForCycle
if(match == false){ //no match found
numOfVars++; //number of variables for allocation
tmp = (varData*)realloc(dynamicData, numOfVars * sizeof(varData));
if(!tmp) { //or equal to NULL
//printf("Could not resize/reallocate memory %i times \n", numOfVars);
}
else{
dynamicData = tmp;
//printf("Reallocated memory %i times \n", numOfVars);
strcpy((dynamicData+numOfVars-1)->varName, buffer);
printf("%s \n", (dynamicData+numOfVars-1)->varName);
}
}
}
varOrNum = 0; //if varOrNum is a number (1)
memset(buffer,'\0',10);
}
}
else{
buffer[i] = oneChar;
i++;
}
} //endWhileCycle (!feof(fSource))
fclose (fSource);
return numOfVars;
}
Inside condition if(match == false) I am reallocating memory through pointer and copying to newly allocated part a "string" from buffer after that I am printing it out to console. Everything works fine until program leaves the function and return value I lost my data from memory.
Can anybody help me here how to use these pointers in argument to obtain values from function and not loose it after function is over? Because right now it doesnt give me any sense why data in memory are lost as I am returning them through pointer.
If I rewrite this funtion to only basic code in MAIN it works.
Thank you very much for any help. I am totally desperate.
I'm having a problem in C when listing the files from a folder.
The strange here is that it works fine several times, but then the program is calling other functions and after that run again then the function to list the files.
I added a print malloc_usable_size - it says that has enough space but when it breaks out it says 0.
Also when is broken out the ent->d_name has some strange characters.
At the end finishes with an error: realloc(): invalid next size
Do you have any idea?
Here is the code:
struct dirent *ent;
int size = 6;
char *file_names = NULL, *temp = NULL;
while((ent=readdir(dirp))!=NULL) {
if( (strcmp(ent->d_name, ".")!=0) && (strcmp(ent->d_name, "..")!=0) ) {
size += strlen(ent->d_name)*sizeof(char) + 6;
temp = file_names;
file_names = (char *) realloc(file_names, size);
if(file_names != NULL) {
strcat(file_names, ent->d_name);
strcat(file_names, "\n\0");
}
else {
file_names = temp;
}
}
}
closedir(dirp);
if(file_names != NULL) {
strcat(file_names, "\0");
}
strcat appends to the end of a string. But you never start off with a string; the first call to realloc gets you uninitialized memory. Perhaps it chances that you get a zero byte the first time, but after other functions have used and freed memory, next time you allocate memory it started with a non-zero byte.
You'll need to set file_names[0] = 0; after the first allocation. (e.g. if ( temp == NULL ) file_names[0] = 0;
BTW it's more usual to use this pattern for realloc: (and don't cast it)
temp = realloc(file_names, size);
if ( temp != NULL )
{
if ( file_names == NULL )
temp[0] = 0;
file_names = temp;
strcat(file_names, ent->d_name);
strcat(file_names, "\n"); // extra \0 is redundant
}
NB. The algorithm is rather inefficient (every call to strcat has to scan the whole string again). You could instead store the current offset; this would also fix your problem with the initial strcat. E.g. (pseudocode)
// before loop
size_t offset = 0;
// in the loop; after allocating the right amount of memory as before
offset += sprintf(file_names + offset, "%s\n", ent->d_name);