I'm having some trouble with some memory issues. The issue is when the line is freed (free(line)), there is a
free(): invalid size error.
From what I know, sscanf doesn't modify the string that is passed into it. Weirdly enough, the free(line) inside the if statement works fine. I'm not sure what the problem is because I've freed the char* like this in other parts of my program without issues, albeit without the sccanf call. Any help would be appreciated.
char* line;
read_line(read, &line, 0);
printf("%s\n", line); //gives "playinfoA/30"
char playerLetter[1];
char numberOfPlayers[2];
char temp[1];
if (sscanf(line, "playinfo%1s%1s%s", playerLetter, temp,
numberOfPlayers) != 3) {
free(line);
return -1;
}
//free(line);
return 0;
If your problem is, free(line) doesn't work when if block fails, then you might want to check if line is actually pointing to something.
Since you did not initialize line, which is a pointer to char, the only other possibility of having it point to some memory location is the call to read_line.
Now, I'm not sure what read_line does, but try passing line instead of &line ?
Related
I'm trying to implement a function that concatenate two strings, but I keep getting the same error.
"pointer being realloc'd was not allocated"
When I compiled the same code on a windows machine it worked, is it something that I'm missing?
The code below is basically what I'm trying to do.
main:
int main() {
int length = 4096;
char *string = malloc(length * sizeof(char));
createString(string, length);
realloc(string, 30);
return 0;
}
createString:
void createString(char * string, int length) {
char *copyAdress = string;
char *temp ="";
int counter2 = 0;
fflush(stdin);
fgets(string, length,stdin);
while(*string != EOF && *string != *temp ) {
string++;
counter++;
}
string = copyAdress;
realloc(string, (counter)*sizeof(char));
}
Thanks!
Edit:
I want createString to change the size of string to the length of the string that I get with fgets, while having the same address as the string that I sent in, so I can allocate more memory to it later when I want to add another string to it.
There are several issues:
realloc(string, (counter)*sizeof(char)); is wrong, you need string = realloc(string, (counter)*sizeof(char)); because realloc may return a different address.
Calling createString(string, length); won't modify string
If you want a more accurate answer you need to tell us what exactly createString is supposed to do. In your code there is no attempt to concatenate two strings.
Let's work through this in order of execution.
fflush(stdin); is undefined behaviour. If you really need to clear everything in the stdin you have to find another way (a loop for example). There are compilers/systems with a defined implementation but I would not count on it.
string++; is superflous as you overwrite string after the loop.
realloc(string, (counter)*sizeof(char));
should be
char *temp = realloc(string, (counter)*sizeof(char));
if (temp != NULL)
string = temp;
This way you get the pointer where your new string is located, but I suggest you read the refecerence for realloc. In essence you do not know if it has been moved and the old address might be invalid from that point on. So dereferencing it is also undefined behaviour.
After this you would have to return the new address of string or pass the address of the pointer to your function.
The same problem repeats with the second realloc. You only got to know your first call was wrong, because the second call noticed that you do not have valid data in what you thought would be your string.
In regards to your comment: It is not possible to use realloc and to be sure that the reallocated memory is in the same place as before.
If you realloc some memory, the pointer pointing to the original memory becomes invalid (unless realloc failed and returned NULL). So calling realloc twice on the same pointer should indeed not work (if it didn't return NULL the first time).
See the answers from others about what you do wrong. However, the eror message means that on MacOS, the realloc in createString deallocated the orignal string and allocated a new one, and now your realloc in main tries to realloc a pointer that is no longer valid (allocated). On Windows, the memory was not deallocated in createString and so the second call of realloc (in main) is given a valid pointer.
I'm getting a segmentation fault when running the code below.
It should basically read a .csv file with over 3M lines and do other stuff afterwards (not relevant to the problem), but after 207746 iterations it returns a segmentation fault. If I remove the p = strsep(&line,"|"); and just print the whole line it will print the >3M lines.
int ReadCSV (int argc, char *argv[]){
char *line = NULL, *p;
unsigned long count = 0;
FILE *data;
if (argc < 2) return 1;
if((data = fopen(argv[1], "r")) == NULL){
printf("the CSV file cannot be open");
exit(0);
}
while (getline(&line, &len, data)>0) {
p = strsep(&line,"|");
printf("Line number: %lu \t p: %s\n", count, p);
count++;
}
free(line);
fclose(data);
return 0;
}
I guess it'd have to do with the memory allocation, but can't figure out how to fix it.
A combination of getline and strsep often causes confusion, because both functions change the pointer that you pass them by pointer as the initial argument. If you pass the pointer that has been through strsep to getline again, you run the risk of undefined behavior on the second iteration.
Consider an example: getline allocates 101 bytes to line, and reads a 100-character string into it. Note that len is now set to 101. You call strsep, which finds '|' in the middle of the string, so it points line to what used to be line+50. Now you call getline again. It sees another 100-character line, and concludes that it is OK to copy it into the buffer, because len is still 101. However, since line points to the middle of the buffer now, writing 100 characters becomes undefined behavior.
Make a copy of line before calling strsep:
while (getline(&line, &len, data)>0) {
char *copy = line;
p = strsep(©, "|");
printf("Line number: %lu \t p: %s\n", count, p);
count++;
}
Now line that you pass to getline is preserved between loop iterations.
Look at the expression getline(&line, &len, data) and read the manpage:
If *line is set to NULL and *len is set 0 before the call, then
getline() will allocate a buffer for storing the line. This buffer
should be freed by the user program even if getline() failed.
This should be the case on your first time round the loop (although we can't see where len is declared, let's just assume your real code does this correctly)
Alternatively, before calling getline(), *line can contain a
pointer to a malloc(3)-allocated buffer *len bytes in size. If the
buffer is not large enough to hold the line, getline() resizes it
with realloc(3), updating *line and *len as necessary.
OK, so if line != NULL it must point to a buffer allocated by malloc of size len. The buffer allocated by your first call to getline (as above) satisfies this.
Note it's not good enough for line to point somewhere into that buffer, it must be the beginning.
Now look at the expression strsep(&line,"|") and read the manpage for that:
... This token is terminated by overwriting the delimiter with a
null byte ('\0'), and *line is updated to point past the token
So, the first argument (line) is changed so that you can call strsep again with the same first argument, and get the next token. This means line is no longer a valid argument to getline, because it isn't the start of a malloc'd buffer (and the length len is also now wrong).
In practice, either
getline will try to read len bytes into the buffer you gave it, but since you advanced line by the length of the first token, it writes off the end of your allocated block. This might just damage the heap rather than dying immediately
getline will try to realloc the buffer you gave it, but since it isn't a valid allocated block, you get heap damage again.
While we're here, you also don't check p is non-NULL, but damaging line is the main problem.
Oh, and if you think the problem is allocation-related, try using valgrind - it generally finds the moment things first go wrong.
I am teaching myself C. Right now I'm working on making a shell, based in part on
https://brennan.io/2015/01/16/write-a-shell-in-c/
I'm trying to add pipes like in bash and created a function called "nospace" to eliminate spaces between arguments so that strtok will then separate based on "|".
char* nospace(char *thestring)
{
char* returnline=(char*)malloc(sizeof(char)*50);
int charpos;
charpos=0;
while(*thestring != '\0')
{
if(*thestring!=' '){
returnline[charpos]=*thestring;
charpos++;
}
thestring++;
}
returnline[charpos]='\0';
return returnline;
}
Since I use malloc for the return line I was reading on SO that I need to free it somewhere so since read_args calls nospace I freed it in read_args.
char** read_args(char* line)
{
argamounts=0;
//tokens and strtok was taken from tutorialspoint regarding the strtok function
char**returnargs = (char**) malloc(sizeof(char*)*20);
char* token;
char* linenospace=nospace(line);
//printf("%s\n",linenospace);
token=strtok(linenospace,"|");
//printf("%s first token\n",token);
int argsub=0;
while (token!=NULL)
{
returnargs[argsub]=token;
//printf("%s\n",token); //test that all arguments are read
argamounts++;
token=strtok(NULL,"|");
//printf("%s second token\n",token);
argsub++;
}
//printf("%d",argamounts);
//returnargs[0]=line; //assumes only one arg for now
//cannot free memory here or returnargs is null, why?
//free(linenospace);
//printf("%s returnarg0\n", returnargs[0]);
//printf("%s returnarg1\n", returnargs[1]);
return returnargs;
}
But the shell wasn't reading the arguments and upon inserting all the printf's to find out where the arguments were falling through I realized that freeing "linenospace" drops my arguments. So if strtok returns a pointer which is set to token, and the "elements" of return args are token pointers, is the way that "linenospace" gets freed that I have to free the double pointer in the shell loop function?
void ypsh_loop(void)
{
char *line;
char **args;
int status;
do {
printf("ypsh > ");
line = read_line();
args=read_args(line);
status=shexecute(args);
}while(status);
free(line);
free(args);
}
(I suppose I would have to change the free(args); line to free a double pointer).
Actually in the process of writing this question I downloaded valgrind after a quick search through SO (CentOS is my home OS) and checked for a memory leak. Sure enough there was one and changing "free(args);" to
int freedouble;
for(freedouble=0; freedouble<argamounts; freedouble++)
{
free(args[freedouble]);
}
free(args);
where argamounts is a globally managed variable seemed to have solved the problem. I guess that answers my question but I'll post it here anyway.
Edit:
So apparently the loop function needs to be written this way:
void ypsh_loop(void)
{
char *line;
char **args;
int status;
do {
printf("ypsh > ");
line = read_line();
args=read_args(line);
status=shexecute(args);
free(line);
free(args[0]);
free(args);
}while(status);
}
Moving the free() statements into the do while loop as opposed to outside where they used to be makes sense because the shell keeps looping back and if I keep malloc-ing I need to free over and over.
However, for some reason if I loop through all the args and try to free them I get "Invalid free()" from valgrind. I have to free args[0] or the memory leaks, but I can only free args[0] and no more.
Adding:
printf("amount of args %i\n",argamounts);
int freedouble;
for(freedouble=0; freedouble<argamounts; freedouble++)
{
printf("argument %d is %s ",freedouble,args[freedouble]);
//free(args[freedouble]);
}
into the do while loop to check if all the arguments were registered indicates that they all are, but I can't free them one by one. I'm going to edit this again once I figure out why but if anybody knows, please tell me.
However, for some reason if I loop through all the args and try to free them I get "Invalid free()" from valgrind. I have to free args[0] or the memory leaks, but I can only free args[0] and no more.
You can't free args[1] etc. since you haven't malloc'ed them. Concerning args[0], you also haven't exactly malloc'ed it, but args[0] points to the first token in the memory space allocated by linenospace=nospace(line), usually at its beginning (unless the line starts with |), thus you can mostly abuse args[0] to free the memory allocated by nospace(line).
However, nospace(line) is useless, since a command with all spaces removed, i. e. all arguments concatenated, is unrecognizable (unless there are no arguments). So, I recommend removing nospace() entirely from your program; then there would be also no additional memory allocation to worry about.
I have a function that reads takes a file (from stdin) ,reads the first 3 lines and concatenates them.
char line[LINESIZE];
char *temp_fd = malloc(sizeof(char)*LINESIZE*3);
char *temp_sm = malloc(sizeof(char)*LINESIZE);
char *temp_nm = malloc(sizeof(char)*LINESIZE);
char temp_pc[LINESIZE];
for(i=0;i<3;i++) {
if (fgets(line, LINESIZE, file) != NULL) {
strcat(temp_fd,line);
if (i==0)
strcpy(temp_sn, line);
else if(i==1)
strcpy(temp_nm, line);
else if(i==2)
strcpy(temp_pc,line);
}
}
I get two errors though in valgrind, and i as i understand, strcat is the problem. How to correctly allocate memory for my pointers? (LINESIZE is 60 btw)
Thank you!
You aren't doing anything to clear out your buffer space before you use it.
There are two different ways you could fix it. Either would work:
Write a null terminator byte to the head of the buffer before using it (e.g. strcpy(temp_fd, "");)
Allocate with calloc instead of malloc
Since temp_fd is uninitialized, you should use strcpy instead of strcat the first time you go through the loop. This would copy the string, rather than trying to append it.
The reason for this is that strcat searches for the location at which to append data before copying the content. However, the content of temp_fd is uninitialized at the time when you call strcat, causing the problem.
Alternatively, you could put '\0' in the initial place of temp_fd right after the allocation, and call strcat in all iterations of the loop:
char *temp_fd = malloc(sizeof(char)*LINESIZE*3);
temp_fd[0] = '\0';
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Pointer to local variable
Can a local variable's memory be accessed outside its scope?
gcc 4.4.4 c89
In main I call a function to pass a line of text to a function. I want to perform some operation on it. However, that would mean that line is of no use. So in my get_string function I copy the contents and return the result. The only problem, is that the memory to that result would be lost and pointing to something unexpected.
I am just wondering how can I pass the result back, without and still keep the ordinal line of data?
Many thanks for any advice,
code snippet from main:
if(fgets(line_data, (size_t)STRING_SIZE, fp) == NULL) {
fprintf(stderr, "WARNING: Text error reading file line number [ %d ]\n", i);
}
if(get_string(line_data) != NULL) {
if(strcmp(get_string(line_data), "END") == 0)
break;
}
else {
fprintf(stderr, "WARNING: Cannot get name of student at line [ %d ]\n", i);
}
/* Fill student info */
strncpy(stud[i].name, line_data, (size_t)STRING_SIZE);
Call this function
char* get_string(char *line_data)
{
char *quote = NULL;
char result[STRING_SIZE] = {0};
strncpy(result, line_data, (size_t)STRING_SIZE);
/* Find last occurance */
if((quote = strrchr(result, '"')) == NULL) {
fprintf(stderr, "Text file incorrectly formatted for this student\n");
return NULL;
}
/* Insert nul in place of the quote */
*quote = '\0';
/* Overwite the first quote by shifting 1 place */
memmove(result - 1, result, strlen(result) + 1);
return result;
}
Just return strdup(result).
It will allocate and copy your string.
However, you have to free the result after using it in the outer function.
You also could take a buffer in input (with its size), and fill it with what you want.
For your direct question - either use malloc(3) and tell the user of the function to de-allocate the return pointer (this is sort of prone to memory leaks since it's so easy to ignore return value in C), or provide the second parameter as a receive buffer:
char* get_string( const char* line_data, char* receive_buf, size_t buf_size );
The third parameter is for the function to know how large the receive buffer is.
Now to your code - the line memmove(result - 1, result, strlen(result) + 1); corrupts your stack.
You want to malloc the memory for result:
char *result; result = malloc(STRING_SIZE);
As you have it, the memory for result exists on the stack and thus only during the time that execution is inside get_string()
You'll also need to free result before returning NULL to prevent a memory leak.
As a rule of thumb, you should never return a pointer to a function's local variable. You know why: once a function returns, the memory allocated for its variables can be reused for something else. The idea to return a pointer to the result buffer is inherently bad.
You should think whether you really need to keep a copy of the quoted string. What if you tested the "END" string before calling get_string? If you need to quote and output data later, it is done easily. Say:
printf("\"%s\"", student_record);
So get_string could actually work in the buffer in place and return the error code (0 for success). Since you know the final result is a smaller nul terminated string, you wouldn't even need a length parameter.
int get_string(char* student_record);
If you really need to keep a copy of the quoted string, then you need to pass another buffer. I'd still return an int to indicate success (0) or failure (say -1).
int get_string( const char* line_data, char* student_record, size_t buf_size );
I personally prefer letting the caller allocate its own buffer. It leaves it a chance to use a fixed length buffer (simpler memory management). Ex:
char student_record[512];
...
if (!get_string(student_record)) {
// error
}