Free a overwritten pointer - c

I have this problem:
char** words = (char**)calloc(10, sizeof(char*));
for (int i = 0; i < 10; i++) {
words[i] = (char*)calloc(100, sizeof(char));
}
I create a array of strings this way. Than in code I overwrite pointers (words[i])
char* str = calloc(strlen(temp), sizeof(char));
//fill str
words[index] = str;
And when I try to free the memory, I get HEAP CORRUPTION DETECTED error.
for (int i = 0; i < 10; i++) {
free(words[i]);
}
free(words);
Is there any way how to do it?

You are lucky to have got an error! Free-ing unallocated memory is just Undefined Behaviour, so it could work during all your tests and only break when you put code in production...
The rule is NEVER erase a malloc-ed pointer before it has been freed. You may have very good reasons to overwrite the words array (I do not know everything in your code) but in that case you could either use two different arrays:
one that you malloc and keep until you free it
one that you initially load from the former, proceed as you need and do not use it for freeing anything.
As a common alternative, you should free the allocated memory before reusing the pointer:
char* str = calloc(strlen(temp), sizeof(char));
//fill str
free(words[index]); // avoid the memory leak
words[index] = str; // correct because str points to another allocated buffer

Thanks! Now I know I have an error in code.
char* str = calloc(strlen(temp)+1, sizeof(char));
This actually solved the HEAP CORRUPTION DETECTED error, but I will repair the code according to your advices.

It's quite easy actually.
You just need to do this:
char** words = (char**)calloc(10, sizeof(char*));
And the to copy the string to a heap address:
words[i]=strdup(temp);
Simple as this.
strdup is a function from <string.h> that is this:
char* strdup(char* s)
{
char* ret=malloc(strlen(s)+1);
strcpy(ret,s);
return ret;
}
It's pointless to allocate and then copy when you can just do it in 1 simple step.

First of all, by saying
words[index] = str;
you're overwriting the previously allocated pointer, thereby losing the actual pointer (returned by initial call to calloc()), causing memory leak. You should use strcpy() to copy the content, not the pointer itself.
Something like
strcpy(words[index], str);
should do the job for you.
Having said that,
char* str = calloc(strlen(temp) , sizeof(char));
also looks wrong. You are probably missing the space for null-terminator while //fill str part. You may need
char* str = calloc(strlen(temp)+ 1, 1); //sizeof char == 1, guaranteed in C

Related

How do I modify the contents of a string literal without using brackets in C?

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.

strcpy seg fault in C

Curious about what is going wrong with this strcpy.
int main(void){
char *history[10];
for(int i = 0; i < 10; i++){
history[i] = NULL;
}
char line[80];
fgets(line,80,stdin);
strcpy(history[0],line); //This line segfaults
}
You've created an array of NULL pointers. You then tried to copy characters onto NULL. That's a no-no.
EDIT:
Your program could be optimized to this:
void main() {
char line[80];
fgets(line,80,stdin);
}
Your history array is never used to generate any output. So, while others have pointed out you need to allocate memory, technically, you could simply do this:
history[0] = line;
That will be a valid pointer up until the line goes out of scope, which is when history goes out of scope so it won't matter.
You need to allocate memory for history[0]. As history[0] is assigned NULL referencing it or writing to it will/may cause segfault.
something like
//this will create memory for 100 chars
history[0] = malloc(sizeof(char) * 100);
strcpy(history[0],line);
Or
//shortcut for both - this allocate new memory and returns pointer.
history[0] = strdup(line);

Parsing CSV Values in C

I am trying to write a basic CSV parser in C that generates a dynamic array of char* when given a char* and a separator character, such as a comma:
char **filldoc_parse_csv(char *toparse, char sepchar)
{
char **strings = NULL;
char *buffer = NULL;
int j = 0;
int k = 1;
for(int i=0; i < strlen(toparse); i++)
{
if(toparse[i] != sepchar)
{
buffer = realloc(buffer, sizeof(char)*k);
strcat(buffer, (const char*)toparse[i]);
k++;
}
else
{
strings = realloc(strings, sizeof(buffer)+1);
strings[j] = buffer;
free(buffer);
j++;
}
}
return strings;
}
However, when I call the function as in the manner below:
char **strings = filldoc_parse_csv("hello,how,are,you", ',');
I end up with a segmentation fault:
Program received signal SIGSEGV, Segmentation fault.
__strcat_sse2 () at ../sysdeps/x86_64/multiarch/../strcat.S:166
166 ../sysdeps/x86_64/multiarch/../strcat.S: No such file or directory.
(gdb) backtrace
#0 __strcat_sse2 () at ../sysdeps/x86_64/multiarch/../strcat.S:166
#1 0x000000000040072c in filldoc_parse_csv (toparse=0x400824 "hello,how,are,you", sepchar=44 ',') at filldocparse.c:20
#2 0x0000000000400674 in main () at parsetest.c:6
The problem is centered around allocating enough space for the buffer string. If I have to, I will make buffer a static array, however, I would like to use dynamic memory allocation for this purpose. How can I do it correctly?
Various problems
strcat(buffer, (const char*)toparse[i]); attempts to changes a char to a string.
strings = realloc(strings, sizeof(buffer)+1); reallocates the same amount of space. sizeof(buffer) is the size of the pointer buffer, not the size of memory it points to.
The calling function has no way to know how many entries in strings. Suggest andding a NULL sentinel.
Minor: better to use size_t rather than int. Use more descriptive names. Do not re-call strlen(toparse) repetitively. Use for(int i=0; toparse[i]; i++) . Make toparse a const char *
You have problems with your memory allocations. When you do e.g. sizeof(buffer) you will get the size of the pointer and not what it points to. That means you will in the first run allocate five bytes (on a 32-bit system), and the next time the function is called you will allocate five bytes again.
There are also many other problems, like you freeing the buffer pointer once you assigned the pointer to strings[j]. The problem with this is that the assignment only copies the pointer and not what it points to, so by freeing buffer you also free strings[j].
Both the above problems will lead to your program having undefined behavior, which is the most common cause of runtime-crashes.
You should also avoid assigning the result of realloc to the pointer you're trying to reallocate, because if realloc fails it will return NULL and you loose the original pointer causing a memory leak.

Memory Clobbered

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

What's wrong with strcpy()? (Segmentation fault) [duplicate]

This question already has answers here:
Crash or "segmentation fault" when data is copied/scanned/read to an uninitialized pointer
(5 answers)
Closed 3 years ago.
What is wrong with strcpy() in this code?
void process_filedata(char *filename)
{
void* content;
const char * buffer;
char * temp;
char * row;
char * col;
int lsize,buflen,tmp,num_scan; //num_scan - number of characters scanned
int m=0,p=0,d=0,j=0; //m - machine, p - phase, d- delimiter, j - job
FILE *file_pointer = fopen("machinetimesnew.csv","r");
if(file_pointer == NULL)
{
error_flag = print_error("Error opening file");
if(error_flag) exit(1);
}
fseek(file_pointer, 0 ,SEEK_END);
lsize = ftell(file_pointer);
buflen = lsize;
rewind(file_pointer);
// content = (char*) malloc(sizeof(char)*lsize);
fread(content,1,lsize,file_pointer);
buffer = (const char*) content;
strcpy(temp,buffer);
row = strtok(temp,"\n");
...............
...............
I am getting a segmentation fault..
You're not allocating any space for temp. It's a wild pointer.
There are actually three segmentation faults here:
fread(content,1,lsize,file_pointer);
strcpy(temp,buffer);
row = strtok(temp,"\n");
The first one is fread() which is attempting to write to memory that does not yet exist as far as your process is concerned.
The second one is strcpy(), (expounding on the first) you are attempting to copy to a pointer that points to nothing. No memory (other than the pointer reference itself) has been allocated for temp, statically or dynamically.
Fix this via changing temp to look like this (allocating it statically):
char temp[1024];
Or use malloc() to dynamically allocate memory for it (as well as your other pointers, so they actually point to something), likewise for content. If you know the needed buffer size at compile time, use static allocation. If not, use malloc(). 'Knowing' is the subject of another question.
The third one is strtok() , which is going to modify temp en situ (in place), which it obviously can not do, since temp was never allocated. In any event, don't expect temp to be the same once strtok() is done with it. By the name of the variable, I assume you know that.
Also, Initializing a pointer is not the same thing as allocating memory for it:
char *temp = NULL; // temp is initialized
char *temp = (char *) malloc(size); // temp is allocated if malloc returns agreeably, cast return to not break c++
Finally, please get in the habit of using strncpy() over strcpy(), its much safer.
Nothing's wrong with strcpy. You haven't initialised temp.
There's yet another mistake. fread does not add a nul character to the end of the buffer. That's because it only deals with arrays of bytes, not nul-terminated strings. So you need to do something like this:
content = malloc(lsize + 1);
fread(content,1,lsize,file_pointer);
content[lsize] = 0;
temp = malloc(lsize + 1);
strcpy(temp, content);
or this:
content = malloc(lsize);
fread(content,1,lsize,file_pointer);
temp = malloc(lsize + 1);
memcpy(temp, content, lsize);
temp[lsize] = 0;
(Also, in real code you should check the results of fread and malloc.)
you didn't allocate memory for temp
char * temp hasn't been initialized and you consequently haven't allocated any memory for it.
try:
temp = (char *)malloc(SIZE);
where SIZE is however much memory you want to allocate for temp
This piece of code intrigues me:
if(file_pointer == NULL)
{
error_flag = print_error("Error opening file");
if(error_flag) exit(1);
}
Shouldn't you exit unconditionally if the file_pointer is NULL?

Resources