This piece of code causes segmentation fault:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SLIDINGWINDOW 5
#define SEGMENTSIZE 100
int main() {
char** send_buffer = (char**) malloc (SLIDINGWINDOW);
int i;
for (i = 0; i<SLIDINGWINDOW; ++i) {
send_buffer[i] = (char*) malloc (SEGMENTSIZE);
}
for (i = 0; i<SLIDINGWINDOW; ++i) {
strcpy(send_buffer[i], "Hello, world");
printf("%s\n", send_buffer[i]);
fflush(NULL);
}
}
The strange thing is if you put the content of the second loop into the first loop, it works!
Could anyone see why this happens?
Many thanks!
The size passed to malloc() isn't correct. You probably meant:
char** send_buffer = malloc (SLIDINGWINDOW * sizeof(send_buffer[0]));
and
send_buffer[i] = malloc (SEGMENTSIZE * sizeof(send_buffer[i][0]));
This is because the argument to malloc() is the number of bytes you're asking for, so you need to multiply the length you want by the size of the elements.
In addition, you should also check that the value returned from malloc() isn't NULL.
Note that I've removed the cast from the malloc call - in C, the cast isn't required, and can sometimes mask an error.
A further improvement would be to use strncpy() to ensure that you're not going to write characters after the end of the segment:
strncpy(send_buffer[i], "Hello, world", SEGMENTSIZE);
Note that in the case that the source string is larger than SEGMENTSIZE, then the destination string will not be null terminated. You can fix this with a:
send_buffer[i][SEGMENTSIZE - 1] = '\0';
after the strncpy().
This will produce only enough space for SLIDINGWINDOW bytes:
malloc (SLIDINGWINDOW)
You want enough space for SLIDINGWINDOW pointers:
malloc (SLIDINGWINDOW * sizeof(char*))
Your second malloc() is correct by luck; sizeof(char) is always 1.
Related
Considering the toy-code as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING_LENGTH (5000)
typedef struct request_body_s {
char *data;
size_t size; // in bytes
} request_body_t;
int do_something(request_body_t *request_body) {
char* content = read_content_elsewhere("/dir/content");
size_t size = strlen(content) * sizeof(char);
request_body->data = (char *) realloc(request_body->data, size + 1);
if (request_body->data == NULL)
return 0;
else {
request_body->size = size;
strncpy(request_body->data, content, MAX_STRING_LENGTH);
return 1;
}
}
int main(int argc, char *argv[]) {
request_body_t request_body;
request_body.data = malloc(1);
request_body.size = 0;
if (do_something(&request_body))
printf("Read!\n");
else {
printf("Error!\n");
exit(0);
}
free(request_body.data);
request_body.size = 0;
}
This code seems work fine until free(request_body.data) is called; it generates an error as follows:
*** free(): invalid next size (fast): 0x0000000001594570 ***
What is (of course) wrong and why? Thanks for any suggestion.
I believe the issue is right here:
strncpy(request_body->data, content, MAX_STRING_LENGTH);
depending on your goal (not clear from your description), I would suggest:
strncpy(request_body->data, content, size > MAX_STRING_LENGTH ? MAX_STRING_LENGTH : size );
strncpy copies the first n chars of the string, that is 5000 in your case. If the source string is smaller that n (5000 here), the rest is padded with zeros, therefore you are accessing further that the end of your bufffer, which leads to undefined behaviour.
You need:
strcpy(request_body->data, content);
It is safe here to use strcpy because we can be sure that the memory allocated by realloc is large enough, because you realloc strlen(content) + 1 chars.
BTW * sizeof(char) is always 1 by definition, so the * sizeof(char) is not necessary.
As written in the strncpy manual,
If the length of src is less than n, strncpy() writes additional null bytes to dest to ensure that a total of n bytes are written.
So, by using strncpy(request_body->data, content, 5000);, you write many '\0' outside your buffer. You shouldn't ever do that, it's an undefined behaviour, and, in this case, you're writing on the 'metadata' used by free, so it crashes.
Here, it would be preferable to use strcpy (and make sure to add a '\0' at the end), or memcpy, because you know the size you want to write.
Also, casting the return of malloc is useless, and sizeof(char) is and will very probably always be 1, so it's also useless.
I was trying to learn the memory management of c.
I allocated the memory for
1. char** a
2. char** b
3. char* b[0] ~ b[99]
and
I freed the memory for
1. char** a
2. char* b[0] ~ b[99]
3. char** b
However, I got an error at the line33, which is free(b[0])
Why does it produces invalid next size free (fast)?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char** a = (char**)malloc(100 * sizeof(char*));
a[0] = "Hello Again!";
char** b = (char**)malloc(100 * sizeof(char*));
int i = 0;
for(i = 0; i < 100; i++){
b[i] = (char*)malloc(10 * sizeof(char));
}
strcpy(b[0], *a);
free(a);
printf("%s", b[0]);
for(i = 0; i < 100; i++){
free(b[i]);
}
free(b);
return 0;
}
The string "Hello Again!" is 13 characters long (including the terminating \0).
The memory you allocate for it is not enough (you allocate just 10 chars), so when calling strcpy you are overwriting past the allocated memory, and probably overwriting the memory location used by the library to keep track of allocations.
The next time that the library will try and use the information stored there, it finds that it is inconsistent, so it aborts with the error you mentioned. That is only one of the many messages that the library can print if it is able to find any such discrepancy.
In general, do not rely on the library flagging those errors for you: in this case you were "lucky" that the info were corrupted in a recognizable way. If you are unlucky, your program might just exhibit undefined behavior.
For each b[i], you only allocate space for 10 chars, but the strcpy copies the string "Hello Again!", which is certainly more than 10 chars. This is undefined behavior.
When you execute this line,
strcpy(b[0], *a);
you are writing over memory that you were not supposed to use. That leads to undefined behavior.
Some environments store useful information at the end of the allocated block of memory. By writing over that memory, you have destroyed that useful information.
The error is this line:
strcpy(b[0], *a);
You allocate 10 bytes for b[0], but you copy 13 bytes, thereby writing beyond the end of the allocated memory.
It's a buffer overrun because strlen(a[0]) + 1 > 10. You need to allocate more than 10 characters for b[0], specifically at least strlen(a[0]) + 1.
this is just a test code i've been using to figure out how the code works before impelmenting it into my program. basically the same issue happens in both programs, im able to realloc 2 times then it crashes. the final project is a 2d pointer, list length and size lengths. ach of these has to be able to be resized to reasonable limits.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char** tasks;
char buff[1089];
int size, i, list_size=1;
tasks = (char**)malloc(list_size * sizeof(char*));
printf("input a string!\n");
gets(buff);
*tasks[0]=(char*)malloc((strlen(buff)+1));
tasks[0]=buff;
printf("%s\n", tasks[0]);
for (i=1;i<8 ;i++){
list_size++;
printf("%d\n", list_size);
*tasks = realloc(*tasks, list_size* sizeof(char*));
printf("input a string!\n");
gets(buff);
*tasks[i]=(char*)malloc((strlen(buff)+1));
tasks[i]=buff;
printf("%s\n", tasks[i]);
}
free(tasks);
return 0;
}
what am i messing up with here?
Several problems here.
*tasks[0]=(char*)malloc((strlen(buff)+1));
As pointed out by David Heffernan in the comments, you are assigning a pointer to a char. You probably just meant to assign to tasks[0].
tasks[0]=buff;
This is not how you copy a string. You're setting tasks[0] to point to your fixed buffer, and leaking the memory you allocated in the previous step.
*tasks = realloc(*tasks, list_size* sizeof(char*));
This is not a safe way to realloc, and you are also reallocing the wrong pointer (the first entry in the list, rather than the list itself). If the allocation fails, you have lost the original pointer, and leaked that memory. You should realloc to a temporary variable first, like this:
char *temp = realloc(tasks, list_size* sizeof(char*));
if (temp != NULL)
tasks = temp;
And finally, don't cast the result of malloc().
I want to make a list of , for example 10 sentences that are entered through the keyboard. For getting a line I am using a function getline(). Can anybody explain why does this program crash upon entering the second line? Where is the mistake ?
#define LISTMAX 100
#define LINEMAX 100
#include <stdio.h>
#include <string.h>
void getline(char *);
int main ()
{
char w[LINEMAX], *list[LISTMAX];
int i;
for(i = 0; i < 10; i++)
{
getline(w);
strcpy(list[i], w);
}
for(i = 0; i < 10; i++)
printf("%s\n", list[i]);
return 0;
}
void getline(char *word)
{
while((*word++ = getchar()) != '\n');
*word = '\0';
}
A string is a block of memory (an array), which contains chars, terminated by '\0'. A char * is not a string; it's just a pointer to the first char in a string.
strcpy does not create a new string. It just copies the data from one block of memory to another. So your problem is: you haven't allocated a block of memory to hold the string.
I'll show you two solutions. The first solution is: change the declaration of list so that the memory is already allocated. If you do it this way, you can avoid using strcpy, so your code is simpler:
// no need for w
char list[10][LISTMAX];
// ...
// get the line straight into list
// no need to copy strings
getline(list[i]);
But if you want to stretch yourself, the second solution is to allocate the block of memory when you know you'll need it. You need to do this a lot in C, so maybe now is a good time to learn this technique:
#include <stdlib.h> // include the malloc function
// ...
char w[LINEMAX], * list[LISTMAX]
// put this line between the getline and strcpy lines
list[i] = (char *) malloc((strlen(w) + 1) * sizeof(char));
This solution is more complicated, but you only allocate as much memory as you need for the string. If the string is 10 characters long, you only request enough memory to hold 11 characters (10 characters + '\0') from the system. This is important if, say, you want to read in a file, and you've no idea how big the file will be.
By the way, why do you have LINEMAX and LISTMAX as separate constants? Can you think of a reason why they might be different? And why haven't you made 10 a constant? Wouldn't this be better?
#define LINEMAX 100
#define NUMBER_OF_LINES 10
// ...
char list[NUMBER_OF_LINES][LINEMAX];
// ...
for (i = 0; i < NUMBER_OF_LINES; i++)
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num = 1;
char* test[8];
sprintf(test[0],"%d",num);
printf("%s\n",test[0]);
}
char *test[8] is an array of 8 char *, or pointers to strings, and since you don't specify, they're all set to garbage values. So sprintf is trying to write data to who-knows-where.
You should use char test[8] instead, which allocates an array of 8 char, and then sprintf(test, "%d", num);.
UPDATE: If you want to use char * pointers, you should allocate space:
char *test = malloc(8 /* see note below */);
sprintf(test, "%d", num);
If you want to use an array of char * pointers, it works the same:
char *test[8]; // 8 pointers to strings
test[0] = malloc(8); // allocate memory for the first pointer
sprintf(test[0], "%d", num);
Keep in mind you would have to call malloc for each of test[0] through test[7] individually.
Also, as mentioned in the comments, if your compiler supports it you should use snprintf(). It's like sprintf but it takes an extra parameter which is the size of the buffer:
snprintf(test, 8, "%d", num);
and guarantees not to use more space than you allow it. It's safer, and if you need to, snprintf returns the amount of space it actually wanted, so if you gave it too little room you can realloc and try again.
Note: some will say this should be malloc(8 * sizeof(char)) (or sizeof *test). They are wrong (in my objectively-correct opinion; note the sarcasm)! sizeof(char) is guaranteed to be 1, so this multiplication is unnecessary.
Some advocate the usage of TYPE *p = malloc(x * sizeof *p) so that if TYPE changes, you'll only need to change it in one place, and sizeof *p will adapt. I am one of these people, but in my opinion you will rarely need to upgrade a char * to another type. Since so many functions use char * and would need to be changed in such an upgrade, I'm not worried about making malloc lines more flexible.
sprintf() does not allocate space for the string; you must do that yourself beforehand.
Look at your warnings:
test.c: In function ‘main’:
test.c:8: warning: ‘test[0]’ is used uninitialized in this function
You allocate an array of 8 pointers, but use one without initializing it. You must call malloc and store the result in test[0] before you can write to the memory pointed to by test[0]. You free it at the end.
A useful function, present in GNU and BSD, is asprintf, which will call malloc for you to allocate enough memory for the formatted string:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int num = 1;
char* test[8];
asprintf(&test[0],"%d",num);
printf("%s\n",test[0]);
free(test[0]);
return 0;
}
(Note that you pass the address of your pointer to asprintf — since your pointer is test[0], its address is &test[0].)
You did allocate space but you you are passing the wrong thing. Try this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num = 1;
char test[8];
sprintf(test,"%d",num);
printf("%s\n",test);
}
int main()
{
char *str[5];
sprintf(str[0], "%d",55);
printf("%s\n",str[0]);
return 0;
}
This will be work. But, if you specify variable instead of integer constant value show the segmentation fault will be occur. This error will be happened at the time of sprintf function execution. Because user space memory access.