when I compile this piece of code, the pointer freed not allocated error pops up. Could someone please explain why that is? Thank you!
static int make_buffer(FILE *input, char *buffer[]){
*buffer = (char *)malloc(INIT_BUFFER_SIZE*sizeof(char));
int buffer_size = INIT_BUFFER_SIZE;
int txt_size = 0;
char cha;
while((cha = fgetc(input)) != EOF){
if (txt_size == buffer_size){
*buffer = (char *)realloc(buffer, buffer_size*2*sizeof(char));
buffer_size *= 2;
}
(*buffer)[txt_size] = cha;
txt_size ++;
}
free(*buffer);
return txt_size;
}
It means that the code is attempting to free something that was not allocated using malloc/realloc. In your case, I think the problem is in
*buffer = (char *)realloc(buffer, buffer_size*2*sizeof(char));
which should be
*buffer = realloc(*buffer, buffer_size*2);
Probably also want to check the result of realloc just for form. Note I simplified yours a bit in that sizeof(char) == 1 by definition and the cast shouldn't be needed these days (it used to be). The commend by David S. about the usefulness of freeing the result is also valid.
Related
I have just coded splitting string into words.
if char *cmd = "Hello world baby", then argv[0] = "Hello", argv[1] = "world", argv[2] = "baby".
strdup function cannot be used, and I want to implement this using malloc and strcpy.
my code is below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define buf_size 128
int main() {
char *argv[16];
memset(argv, 0, sizeof(argv));
int words = 0;
char *cmd = "Hello world baby";
unsigned int len = strlen(cmd);
int start = 0;
for(unsigned int i = 0; i <= len; i++){
if(cmd[i] == ' ' | cmd[i] == '\0'){
++words;
char *w = (char *)malloc(sizeof(char)*(i-start) + 1);
strcpy(w, cmd + start);
w[i-start] = '\0';
argv[i] = w;
start = i + 1;
}
}
for(int i = 0; i < words; i++){
printf("%s\n", argv[i]);
free(argv[i]);
}
return 0;
}
I hoped that the printf function produces:
Hello
world
baby
However, when the printf() function is reached, the program triggers a segmentation fault.
Your primary problem, despite the banter in the comments about how to write your own version of strdup(), is that you really need strndup(). Eh?
You have the line:
strcpy(w, cmd + start);
Unfortunately, this copies the whole string from cmd + start into the allocated space, but you only wanted to copy (i - start) + 1 bytes including the null byte, because that's all the space you allocated. So, you have a buffer overflow (but not a stack overflow).
POSIX provides the function strndup()
with the signature:
extern char *strndup(const char *s, size_t size);
This allocates at most size + 1 bytes and copies at most size bytes from s and a null byte into the allocated space. You'd use:
argv[i] = strndup(cmd + start, i - start);
to get the required result. If you don't have (or can't use) strndup(), you can write your own. That's easiest if you have strnlen(), but you can write your own version of that if necessary (you don't have it or can't use it):
char *my_strndup(const char *s, size_t len)
{
size_t nbytes = strnlen(s, len);
char *result = malloc(nbytes + 1);
if (result != NULL)
{
memmove(result, s, nbytes);
result[nbytes] = '\0';
}
return result;
}
This deals with the situation where the actual string is shorter than the maximum length it can be by using the size from strnlen(). It's not clear that you are guaranteed to be able to access the memory at s + nbytes - 1, so simply allocating for the maximum size is not appropriate.
Implementing strnlen():
size_t my_strnlen(const char *s, size_t size)
{
size_t count = 0;
while (count < size && *s++ != '\0')
count++;
return count;
}
"Official" versions of this are probably implemented in assembler and are more efficient, but I think that's a valid implementation in pure C.
Another alternative in your code is to use the knowledge of the length:
char *w = (char *)malloc(sizeof(char)*(i - start + 1));
memmove(w, cmd + start, i - start);
w[i-start] = '\0';
argv[i] = w;
start = i + 1;
I note in passing that multiplying by sizeof(char) is a no-op since sizeof(char) == 1 by definition. You should include the + 1 in the multiplication in general (as I've reparenthesized the expression). If you were dealing with some structure and wanted N + 1 structures, you need to use (N + 1) * sizeof(struct WhatNot) and not N * sizeof(struct WhatNot) + 1. It's a good idea to head off bugs caused by sloppy coding practices while you're learning, even though there's no difference in the result here.
There are those who excoriate the cast on the result of malloc(). I'm not one of them: I learned to program on a pre-standard C system where the cast was crucial because the char * address of an object was different from the address of the same memory location when referenced via a pointer to a type bigger than a char. That is, the short * address and char * address for the same memory location had different bit patterns. Not casting the result of malloc() led to crashes. (I observe that the primary excuse given for rejecting the cast is "it may hide errors if malloc() is not declared". That excuse went by the wayside when C99 mandated that functions must be declared before being used.)
Warning: no compiler was consulted about the validity of any of the code shown in this answer. Nor was the sanity of the overall algorithm tested.
You have:
if(cmd[i] == ' ' | cmd[i] == '\0'){
That | should be ||.
i was playing arround with the C malloc and free tools and i had a weird memory leak. Does someone has an idea about it?
The goal is to successfully free a char**.
So in the function freezer, i free every char* in the char** and the i free the char**.
But Valgrind (my leaks detector on linux) find 20 bytes in 4 blocks leaked (i don't know if i can write 'leaked' XD)
The more interesting part is that if i do a bigger char** by adding a char* in it, it leak 5 more bytes of memory in another block :/.
#include <stdio.h>
#include <stdlib.h>
void freezer(char ***array, int length){
int i;
i = -1;
while (*array[++i] != NULL){
free(*array[i]);
}
free(*array);
}
int main(){
char **big;
int len = 4;
int i;
big = malloc(sizeof(char *) * (len + 1));
i = -1;
while (++i < len){
big[i] = malloc(sizeof(char) * 5);
big[i][0] = 't';
big[i][1] = 'e';
big[i][2] = 's';
big[i][3] = 't';
big[i][4] = '\0';
}
big[i] = NULL;
i = -1;
while (++i < len){
printf("i: %d\t%s\n", i, big[i]);
}
freezer(&big, len);
return (0);
}
You can directly copy/past/run the code as it is.
So if you have any clue about the error/C problem, please let me know.
big[i] = NULL; causes a buffer overflow. You only allocated space for a total of len entries, plus one byte; but at that point i == len.
Perhaps you meant big = malloc(sizeof(char *) * (len + 1));
Also, the freezer function dereferences and frees the wrong thing. Either change it to accept char **array , or replace all occurrences of array with (*array) inside the function. The former is preferable, there is no need to pass by reference in order to call free.
Your loop structure is weird for no apparent reason; it's normal to use:
for (i = 0; i < len; ++i)
which is the same logic but will make your code easier to digest for people reading it.
Also, don't cast malloc
There is my C code, it is a leetcode problem, and I got "Runtime Error". So I recompile in VS2013, the problem is free(++tmp), why? I can't get it, I writen C code like that, just want to known more things about pointer.
#include <stdio.h>
#include <stdlib.h>
/* Add binary.
* a = "11", b = "1"
* result = "100"
*/
char *add_binary(char *a, char *b);
int main()
{
printf("%s\n", add_binary("10", "1"));
printf("%s\n", add_binary("1111", "1111"));
return 0;
}
char *add_binary(char *a, char *b)
{
int alen = 0, blen = 0, sum = 0;
int len;
char *tmp, *result;
while(*a++) alen++;
while(*b++) blen++;
a -= 2;
b -= 2;
len = alen > blen ? alen : blen;
tmp = (char *)malloc(len*sizeof(char));
printf("%p\n", tmp);
while(*a || *b){
if(*a){
sum += *a - '0' + 0;
a--;
}
if(*b){
sum += *b - '0' + 0;
b--;
}
if(sum > 1){
*tmp++ = 3 == sum ? '1' : '0';
sum = 1;
} else {
*tmp++ = 1 == sum ? '1' : '0';
sum = 0;
}
}
*tmp = '\0';
len += 1 == sum ? 1 : 0;
result = (char *)malloc(len*sizeof(char));
if(1 == sum){
*result++ = '1';
}
while(*(--tmp)){
*result++ = *tmp;
}
*result = '\0';
printf("%p\n", tmp);
free(++tmp);
tmp = NULL;
return (result-len);
}
You can only pass to free the resulting pointer value of malloc:
tmp = (char *)malloc(len*sizeof(char));
then
free(tmp);
is OK.
But free(++tmp) or free(tmp + 42) is not OK and invokes undefined behavior.
Stop modifying the mallocated pointer before freeing it. If you want to use pointer arithmetic, eg '*tmp++', then keep a copy of the original so that the space can be freed.
I have no clue why you would do 'free(++tmp);'. It makes no sense though, by that time, you've already totally shagged up tmp by incrementing it in the while loop:(
Edit: BTW, you've screwed 'result' as well. You are returning a malloced and bodged pointer that cannot be correctly freed by the caller.
Whatever 'clever' thing you are attempting with the pointer manipulations, stop it. It's too easy to get it wrong!
Here is a slightly more detailed response from the other answer.
The pointer is an address for which you allocate memory. When you pass in an address to free that has been previously malloc'd there is no problem. The problem is that you are not passing in the address of a malloc'd space. You are passing in the address of something that is potentially within a malloc'd space and as such cannot be freed.
free expects its argument to be the same pointer value that was returned from a previous malloc or realloc call. If you modify that pointer value before passing it to free, then the behavior is undefined and Bad Things can happen (this is why it appears to work for one platform and breaks on another; in truth, it's broken for both).
You'll need to preserve the pointer values returned from your malloc calls:
char *tmp, *tmpOrig;
...
tmp = tmpOrig = malloc(len * sizeof *tmpOrig); // note no cast, operand of sizeof
...
/**
* modify tmp to your heart's desire
*/
...
free( tmpOrig );
You'll need to do the same thing for result.
You should not cast the result of malloc, unless you are working with a pre-C89 compiler. It's unnecessary, and under C89/C90 compilers can mask a bug.
I am facing a memory leak condition in the following functions.
char * readdatafromfile(unsigned pageNumber) {
char *buff = (char*) malloc(sizeof(char) * pagesize);
lseek(fd, pagesize * (pageNumber), SEEK_SET);
read(fd, buff, pagesize);
return buff;
}
//Read from file
char * readfromfile(char *fname, int pageno) {
char *buff = NULL;
fd = searchinvector(fname);
if (fd > 0)
buff = readdatafromfile(pageno);
else
printf("\nINDEX is not opened\n");
return buff;
}
I am trying to call the function the following way
char* root_buf = readfromfile(fname,pageno);
Can someone point to me where the memory leak occurs and how to overcome it.
EDIT
I do call free(root_buf); later. Forgot to mention that part. I believe this has to do with the fact that I am creating a pointer and returning it. Maybe the reference is caught in another pointer in the caller function.
The memory allocated using malloc are never freed again.
If you do this from your call site:
char* root_buf = readfromfile(fname,pageno);
// do stuff
free(root_buf);
It should solve the leak.
You are using malloc here.
char *buff = (char*) malloc(sizeof(char) * pagesize);
You need to free the memory after you have used it.
After you are done with root_buf and no longer need it:
free (root_buf);
Code rewritten to be more clear
void indexe(char * line, unsigned ref) {
unsigned i = 0;
char word[128]; //(1)
//char * word; //(2)
while(*line) {
if(isalpha(*line))
word[i++] = *line; //(1)
//*word++ = *line; //(2)
*line++;
}
}
int main(int argc, const char * argv[]) {
char line[128];
FILE * f = fopen(argv[1], "r");
unsigned x = 0;
while (fgets(line, 128, f)){
indexe(line, ++x);
}
fclose(f);
return 0;
}
Hello, I have tried the two above combinations:
word[] -> word[i++]
*word -> *word++
The whole thing works flawlessly, except when reaching EOF, in which case the pointers syntax fails with a segmentation fault, but not the array syntax.
I am a C total beginner, could someone explain in beginner terms what happens here, and maybe suggest a solution to fix the pointer syntax? (But mostly explain, please)
This version, as posted, is fine:
void indexe(char * line, unsigned ref) {
unsigned i = 0;
char word[128]; //(1)
//char * word; //(2)
while(*line) {
if(isalpha(*line))
word[i++] = *line; //(1)
//*word++ = *line; //(2)
*line++;
}
}
However, if you recomment the code to use the lines marked //(2) instead, you have this:
char * word; //(2
*word++ = *line; //(2)
Which is simply a case of writing to a pointer you haven't initialised with allocated memory. This isn't allowed. You need to keep it as an array, or use something like malloc to reserve storage. If you want to write the function without using an array at all, the code would be:
char *word = malloc(128); // reserve 128 bytes
if (word == NULL) { // these checks are important
fprintf(stderr, "Cannot allocate memory!");
exit(EXIT_FAILURE);
}
...other stuff...
free(word);
Note also that:
*line++;
increments line, but dereferences it (before it's incremented) for no reason.
The pointer syntax fails because you have defined a pointer char * word; but you have not set it to point to any data - the memory you are pointing to can be anywhere. So, when you execute the following statement:
*word++ = *line;
You are storing the value pointed to by line in the value pointed to by word. Unfortunately, you do not know where word is pointing. As #teppic pointed out, you're writing to a pointer that has not been initialized to allocated memory.
You could malloc that memory as #teppic previously pointed out. You could also do the following:
char reserve[128];
char * word = reserve; // could also have used &reserve[0]
Hope that helps!