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.
Related
I was writing a simple program to see how dynamic memory allocations in C works.
#include <stdio.h>
#include <stdlib.h>
int main() {
char* c = (char* ) malloc(sizeof(char) * 1);
int* a = (int* ) malloc(sizeof(int) * 1);
for (int i = 0; i < 10; i++)
*(a+i) = i;
c = "Hello World";
printf("%c\n", *(c+4));
printf("%d\n", *(a+4));
return 0;
}
The output I get is
o
4
I've allocated enough memory to save a single character and an integer. But then, how is a whole string and an array of integers of length 10 getting saved?
Does the memory automatically get extended? Could someone kindly explain how it works?
Thanks.
In accessing the dynamically allocated array a out of bounds, you invoke undefined behavior. The program may do anything, including "working" the way you expected.
int* a = (int* ) malloc(sizeof(int) * 1);
for (int i = 0; i < 10; i++)
*(a+i) = i;
I will suggest a different syntax, and that you not cast the result of malloc.
int* a = malloc(sizeof(int) * 1);
for (int i = 0; i < 10; i++)
a[i] = i;
As for your string:
char* c = (char* ) malloc(sizeof(char) * 1);
c = "Hello World";
You are allocating one byte of memory and c is pointing to it. You then reassign c to point to a string literal. As a result, you can print c without issue. Since the dynamically allocated memory is no longer pointed to, you cannot free it and a very small memory leak is created.
If you wanted to copy Hello World" into the memory c` pointed to initially, you'd write:
strcpy(c, "Hello World");
But this would access out of bounds for c, and we'd be back in the territory of undefined behavior.
Please note that strings in C require a null terminating character at the end. A single char's memory cannot store a string as it only has room for the null terminator.
The assignment c = "Hello World" just causes c to point to the string literal and the single character allocated has been leaked.
You've written beyond the allocated size of the array a but it's not surprise those addresses are accessible to your program so you don't get a protection/segmentation fault.
Your code then ends before you do anything else with malloc() and free() so you never trip over what memory corruption your for-loop may have introduced.
As comments point out "undefined behaviour" includes your program working as intended.
In my experience overwriting the bounds of dynamically allocated memory often appears to work and then crashes about 3 or more allocations later.
Your program is probably terminating before it trips over the mess you've made of it's memory.
In programming breaking things isn't usually a good way to find out how they work.
Disclaimer: this is for a homework assigment.
Say I have a string that was declared like this:
char *string1;
For part of my program, I need to set string1 equal to another string, string2. I can't use strcpy or use brackets.
This is my code so far:
int i;
for(i = 0; *(string2 + i) != '\0'; i++){
*(string1 + i) = *(string2 + i);
}
This causes a segmentation fault.
According to https://www.geeksforgeeks.org/storage-for-strings-in-c/ , this is because string1 was declared like this: char *string1 and a workaround to avoid segfaults is to use brackets. I can't use brackets, so is there any workaround that I can do?
EDIT: I am also prohibited from allocating more memory or declaring arrays. I cant use malloc(), falloc() etc.
The issue you are having is that string2 does not have memory allocated to it.
Your code is missing some details, but I'll assume it looks something like this:
#include <stdio.h>
int main()
{
char *originalStr = "Hello NewArsenic";
char *newStr;
// YMMV depending on the compiler for this line. Might print (null) for
// newStr or it might throw an error.
printf("Original: %s\nNew: %s\n", originalStr, newStr);
int i;
for (i = 0; *(originalStr + i) != '\0'; i++)
{
*(newStr + i) = *(originalStr + i);
}
printf("Original: %s\nNew: %s\n", originalStr, newStr);
return 0;
}
TL;DR Your Issue
Your issue here is that you are attempting to store some values into newStr without having the memory to do so.
Solution
Use malloc.
#include <stdio.h>
#include <stdlib.h> // malloc(size_t) is in stdlib.h
#include <string.h> // strlen(const char *) is in string.h
int main()
{
char *originalStr = "Hello NewArsenic";
// Note here that size_t is preferable to int for length.
// Generally you want to be using size_t if you are working with size/length.
// More info at https://stackoverflow.com/questions/19732319/difference-between-size-t-and-unsigned-int
size_t originalLength = strlen(originalStr);
// This is malloc's typical usage, where we are asking from the system to
// give us originalLength + 1 many chars.
// The `char` here is redundant, actually, since sizeof(char) is defined to
// be one by the C spec, but you might find it useful to see the typical
// usage of `malloc`.
// Since malloc returns a void *, we need to cast that to a char *.
char *newStr = (char *)malloc((originalLength + 1) * sizeof(char));
// Your code stays the same.
printf("Original: %s\nNew: %s\n", originalStr, newStr);
size_t i;
for (i = 0; *(originalStr + i) != '\0'; i++)
{
*(newStr + i) = *(originalStr + i);
}
// Don't forget to append a null character like I did before editing!
*(newStr + originalLength) = 0;
printf("Original: %s\nNew: %s\n", originalStr, newStr);
// Because `malloc` gives us memory on the stack, we need to tell the system
// that we want to free it before exiting.
free(newStr);
return 0;
}
The long answer
What is a C String?
In C, a string is merely an array of characters. What this means is that for each character you want to have have, you need to allocate memory.
Memory
In C, there are two types of memory allocation - stack- and heap-based.
Stack Memory
You're probably more familiar with stack-based memory than you think. Whenever you declare a variable, you're defining it on the stack. Arrays declared with bracket notation type array[size_t] are stack-based too. What's specific about stack-based memory allocation is that when you allocate memory, it will only last for as long as the function in which it was declared, as you're probably familiar with. This means that you don't have to worry about your memory sticking around for longer than it should.
Heap Memory
Now heap-based memory allocation is different in the sense that it will persist until it is cleared. This is advantageous in one way:
You can keep values of which you don't know the size at compile time.
But, that comes at a cost:
The heap is slower
You have to manually clear your memory once you're done with it.
For more info, check out this thread.
We typically use the function (void *) malloc(size_t) and its sister (void *) calloc(size_t, size_t) for allocating heap memory. To free the memory that we asked for from the system, use free(void *).
Alternatives
You could've also used newStr = originalStr, but that would not actually copy the string, but only make newStr point to originalStr, which I'm sure you're aware of.
Other remarks
Generally, it's an anti-pattern to do:
char* string = "literal";
This is an anti-pattern because literals cannot be edited and shouldn't be. Do:
char const* string = "literal";
See this thread for more info.
Avoid using int in your loop. Use size_t See this thread.
For part of my program, I need to set string1 equal to another string, string2. I can't use strcpy or use brackets.
Perhaps the solution is just as simple as
string2 = string1
Note that this assignes the string2 pointer to point directly to the same memory as string1. This is sometimes very helpful because you need to maintain the beginning of the string with string1 but also need another pointer to move inside the string with things like string2++.
One way or another, you have to point string2 at an address in memory that you have access to. There are two ways to do this:
Point at memory that you already have access to through another variable either with another pointer variable or with the address-of & operator.
Allocate memory with malloc() or related functions.
Here is my code snippet to create the 2D array that holds char array. It would be great if someone could find out what could be the reason. I have tried using both malloc() and calloc() to allocate memory to the 2D array, yet no positive signs.
Code Snippet:
char** attrNames = (char **)malloc(3*sizeof(char*))
for (m = 0; m < 3; m++) {
attrNames[m] = (char *)malloc(2 * sizeof(char*));
strcpy(schema->attrNames[m], temp_buff2[m]);
}
I am trying to allocate the memory and then going on a loop and again allocating memory and copy the data from a variable called temp_buff2 (has character data) into the char array.
Try the code below. Even though memory allocation error in your project might be unlikely, now is a good time to develop a good error handling reflex - it will save your bacon when you move on to more serious projects.
Note that char* pointer needs a buffer that is equal to the length of the string plus one extra byte. sizeof(char*) is a small value, only 8 on a 64-bit architecture - it just stores the value of the memory address where the string starts. Note that we need +1 on top of strlen() because strcpy() will store one extra byte (\0) as a string terminator.
char** attrNames = (char **)malloc(3*sizeof(char*));
if (!attrName)
{
// handle memory error
}
for (m = 0; m < 3; m++) {
attrNames[m] = (char *)malloc(strlen(temp_buff2[m])+1);
if (!attrNames[m])
{
// handle memory error
}
strcpy(schema->attrNames[m], temp_buff2[m]);
}
Memory error can be handled by returning an error code from your function or via a fatal exit like this:
fprintf(stderr, "Out of memory\n");
exit(1);
You will need to #include <stdlib.h> for the prototype of exit().
You need to reserve enough space for whatever you have inside "temp_buff2". For example:
char** attrNames = (char **)malloc(3*sizeof(char*))
for (m = 0; m < 3; m++) {
attrNames[m] = (char *)malloc( strlen(temp_buff2[m]) + 1 );
strcpy(schema->attrNames[m], temp_buff2[m]);
}
Notice that I am adding 1 to the strlen result, this is because we need to reserve an additional byte for the null char terminator.
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.
I am puzzled by this response.Can anyone help me on this and point out where I am making a mistake? The output at codepad is "memory clobbered before allocated block"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *s = (char *)malloc(10 * sizeof(char));
s = "heel";
printf("%s\n",s);
printf("%c\n",s[2]);
printf("%p\n",s);
printf("%d\n",s);
free(s);
return 0;
}
You're trying to free constant memory with:
free(s); // cannot free constant "heel"
What you're doing is allocating a piece of memory and storing its location (char *s). You are then overwriting that reference with one to a string constant "heel" (memory leak), which cannot be freed. To make this behave as desired, you should be copying the constant string to the memory you allocated:
strcpy(s, "heel");
Here is an example for getting user input:
char *input = malloc(sizeof(char) * 16); // enough space for 15 characters + '\0'
fgets(input, 16, stdin);
// do something with input
free(input);
To expand on #TimCooper's answer:
first you do: char *s = (char *)malloc(10 * sizeof(char));
then: s = "heel";
The first line allocates memory and assigns the location of that memory to s. But the second line reassigns s to the memory location of constant string heel on the stack!
Which means you try and free() memory on the stack, which is illegal. AND you leak memory, since what you first allocated to s is now inaccessible.
If you want to write a string into the memory pointed by s, you should use something like strcpy() (or, better, strncpy()).
You cannot free(s) - it's constant memory.
Try to change s = "heel"; with strcpy(s,"heel");
char *s = (char *)malloc(10 * sizeof(char));
s = "heel";
Doesn't do what you think, or what you would expect with more modern languages
The first line allocates some memory for 10chars and returns the address of it.
The second line changes that address to point to a constant block of memory allocated at compile time, containing "heel" losing the link to the allocated memory - leaking it