This question already has answers here:
C - pointer is not null after freeing it
(6 answers)
Why doesn't free(p) set p to NULL?
(9 answers)
Closed 4 years ago.
I use only main() function. Not copying any pointer.
Why free() function not get NULL value?
Whay I can check my wariable is full or empty?
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *e = NULL;
printf("before e=%p\n",(void *)e);
e = malloc(sizeof(int));
*e = 7;
printf("after, e=%p\n",(void *)e);
if(e == NULL) { printf("Problemy z pamięcia\n"); return 0; }
printf(" value = %d\n",*e);
free(e);
printf("after free, e=%p\n",(void *)e);
if(e == NULL) printf("is NULL\n");
return 1;
}
result
before e=0
after, e=464027a0
value = 7
after free, e=0x7f82464027a0
why if(e==NULL) is not true? How do it?
Because C has a call-by-value policy and free is a standard function. Every function call is not modifying its arguments, because formal parameters hold a copy of the argument passed at the call.
In practice, you could use the comma operator and systematically do
free(e), e = NULL;
However, using a pointer (value) after it has been free-d is undefined behavior. Be scared of UB, so learn more about it.
You should compile with all warnings and debug info (so gcc -Wall -Wextra -g if using GCC) and learn to use the gdb debugger. You could use tools like valgrind or address sanitizers, since they are very helpful to hunt bugs such as memory leaks or buffer overflows.
BTW, your code is wrong. You don't test against failure of malloc (your if(e == NULL) is too late, and the preceding *e = 7; is likely to get a segmentation fault when malloc has failed) , and you really should code at least something like:
e = malloc(sizeof(int));
if (!e) { perror("malloc e"); exit(EXIT_FAILURE); };
The !e above could be replaced by e==NULL for readability.
Related
This question already has answers here:
Initializing a pointer in a separate function in C
(2 answers)
Closed 3 years ago.
My goal is to pass a pointer to double to a function, dynamically allocate memory inside of the function, fill resulted array with double values and return filled array. After lurking attentively everywhere in StackOverflow, I have found two related topics, namely Initializing a pointer in a separate function in C and C dynamically growing array. Accordingly, I have tried to write my own code. However, the result was not the same as it was described in aforementioned topics. This program was run using both gcc and Visual Studio.
First trial.
int main()
{
double *p;
int count = getArray(&p);
<...print content of p...>
return 0;
}
int getArray(double *p)
{
int count = 1;
while(1)
{
if(count == 1)
p = (double*)malloc(sizeof(double));
else
p = (double*)realloc(p, count*sizeof(double));
scanf("%lf", &p[count-1]);
<...some condition to break...>
count++;
{
<... print the content of p ...>
return count;
}
(Here comes the warning from compiler about incompatible argument type. Ignore it).
Input:
1.11
2.22
3.33
Output:
1.11
2.22
3.33
0.00
0.00
0.00
Second trial.
int main()
{
double *p;
int count = getArray(&p);
<...print content of p...>
return 0;
}
int getArray(double **p)
{
int count = 1;
while(1)
{
if(count == 1)
*p = (double*)malloc(sizeof(double));
else
{
double ** temp = (double*)realloc(*p, count*sizeof(double));
p = temp;
}
scanf("%lf", &(*p)[count-1]);
<...some condition to break...>
count++;
{
<... print the content of p ...>
return count;
}
Input:
1.11
2.22
Segmentation error.
I tried this method on several different *nix machines, it fails when the loop uses realloc. SURPRISINGLY, this code works perfect using Visual Studio.
My questions are: first code allows to allocate and reallocate the memory and even passes all this allocated memory to main(), however, all the values are zeroed. What is the problem? As for the second program, what is the reason of the segmentation error?
The right way of doing it is like this:
int getArray(double **p)
{
int count = 0;
while(1)
{
if(count == 0)
*p = malloc(sizeof(**p));
else
*p = realloc(*p, (count+1)*sizeof(**p));
scanf("%lf", &((*p)[count]));
<...some condition to break...>
count++;
{
<...print content of p...>
return count;
}
If you pass a pointer to a function and you want to change not only the value it is pointing at, but change the address it is pointing to you HAVE to use a double pointer. It is simply not possible otherwise.
And save yourself some trouble by using sizeof(var) instead of sizeof(type). If you write int *p; p = malloc(sizeof(int));, then you are writing the same thing (int) twice, which means that you can mess things up if they don't match, which is exactly what happened to you. This also makes it harder to change the code afterwards, because you need to change at multiple places. If you instead write int *p; p = malloc(sizeof(*p)); that risk is gone.
Plus, don't cast malloc. It's completely unnecessary.
One more thing you always should do when allocating (and reallocating) is to check if the allocation was successful. Like this:
if(count == 0)
*p = malloc(sizeof(**p));
else
*p = realloc(*p, (count+1)*sizeof(**p));
if(!p) { /* Handle error */ }
Also note that it is possible to reallocate a NULL pointer, so in this case the malloc is not necessary. Just use the realloc call only without the if statement. One thing worth mentioning is that if you want to be able to continue execution if the realloc fails, you should NOT assign p to the return value. If realloc fails, you will lose whatever you had before. Do like this instead:
int getArray(double **p)
{
int count = 0;
// If *p is not pointing to allocated memory or NULL, the behavior
// of realloc will be undefined.
*p = NULL;
while(1)
{
void *tmp = realloc(*p, (count+1)*sizeof(**p));
if(!tmp) {
fprintf(stderr, "Fail allocating");
exit(EXIT_FAILURE);
}
*p = tmp;
// I prefer fgets and sscanf. Makes it easier to avoid problems
// with remaining characters in stdin and it makes debugging easier
const size_t str_size = 100;
char str[str_size];
if(! fgets(str, str_size, stdin)) {
fprintf(stderr, "Fail reading");
exit(EXIT_FAILURE);
}
if(sscanf(str, "%lf", &((*p)[count])) != 1) {
fprintf(stderr, "Fail converting");
exit(EXIT_FAILURE);
}
count++;
// Just an arbitrary exit condition
if ((*p)[count-1] < 1) {
printf("%lf\n", (*p)[count]);
break;
}
}
return count;
}
You mentioned in comments below that you're having troubles with pointers in general. That's not unusual. It can be a bit tricky, and it takes some practice to get used to it. My best advice is to learn what * and & really means and really think things through. * is the dereference operator, so *p is the value that exists at address p. **p is the value that exists at address *p. The address operator & is kind of an inverse to *, so *&x is the same as x. Also remember that the [] operator used for indexing is just syntactic sugar. It works like this: p[5] translates to *(p+5), which has the funny effect that p[5] is the same as 5[p].
In my first version of above code, I used p = tmp instead of *p = tmp and when I constructed a complete example to find that bug, I also used *p[count] instead of (*p)[count]. Sorry about that, but it does emphasize my point. When dealing with pointers, and especially pointers to pointers, REALLY think about what you're writing. *p[count] is equivalent to *(*(p+count)) while (*p)[count] is equivalent to *((*p) + count) which is something completely different, and unfortunately, none of these mistakes was caught even though I compiled with -Wall -Wextra -std=c18 -pedantic-errors.
You mentioned in comments below that you need to cast the result of realloc. That probably means that you're using a C++ compiler, and in that case you need to cast, and it should be (double *). In that case, change to this:
double *tmp = (double*)realloc(*p, (count+1)*sizeof(**p));
if(!tmp) {
fprintf(stderr, "Fail allocating");
exit(EXIT_FAILURE);
}
*p = tmp;
Note that I also changed the type of the pointer. In C, it does not matter what type of pointer tmp is, but in C++ it either has to be a double* or you would need to do another cast: *p = (double*)tmp
This question already has answers here:
How much memory would be freed if pointer is changed in C?
(3 answers)
Closed 5 years ago.
I have written the following code, however I get a crash (without warnings or errors) and do not know the cause:
const int N = 1000;
int main(){
int *pI = calloc(N,sizeof(int));
for (int i=0;i<N;i++) {
*(pI++) = (i+1);
}
free(pI);
return EXIT_SUCCESS;
}
I am thankful for any advice!
You are not releasing the original pointer received from calloc():
free(pI);
You have been modifying the value contained in this pointer:
*(pI++) = (i+1);
Do instead:
int *p = calloc(N,sizeof(int));
int *pI = p;
// ...
free(p);
That is, save the value returned from calloc() and then pass it to free() when you don't need the allocated memory anymore.
This question already has answers here:
Malloc, free and segmentation fault
(4 answers)
Closed 6 years ago.
I'm working on a small private project that reads some links from an html-page source. I read the html file line by line and then check if that line contains "data-cfsrc", which always preceeds a link that I want to read. This works fine, until I try to free the pointer that points to where the keyword ("data-cfsrc") starts.
I've tried freeing it on multiple points and it only works when I haven't done anything with it yet.
Here's my code:
FILE *fp_w, *fp_r;
fp_r = fopen("page.html","r");
fp_w = fopen("bg_list.txt","a");
char line[1024],img[512],c;
//char *imgpoint = malloc(sizeof(char)*512);
char *imgpoint;
int i,imgcount = 0;
while(imgcount<15){
// read line
i = 0;
do{
c = fgetc(fp_r);
line[i] = c;
i++;
}while(c!='\n');
line[i] = '\0';
if(strstr(line,"data-cfsrc") != NULL){
imgpoint = strstr(line,"data-cfsrc");
strcpy(img,imgpoint);
c = 0;
for(i=0; c!=34; i++){
img[i] = img[i+12];
c = img[i+13];
}
img[i] = '\0';
fprintf(fp_w,"%s\n",img);
imgcount++;
printf("imgcount = %d\n",imgcount);
}
}
fclose(fp_r);
fclose(fp_w);
//free(imgpoint);
return 0;
EDIT: as mentioned, I removed the free() entirely, but now my program still results in a Segmentation fault when return is called.
EDIT 2: completely ommitted the impoint pointer. Everything still works, but I still get a Segmentation fault on return.
free() requires you to pass the same pointer that was returned by malloc() (or friends). But here,
imgpoint = strstr(line,"data-cfsrc");
you are reassigning it. Hence undefined behaviour when free() is called.
From free():
The free() function frees the memory space pointed to by ptr, which
must have been returned by a previous call to malloc(), calloc(), or
realloc(). Otherwise, or if free(ptr) has already been called
before, undefined behavior occurs. If ptr is NULL, no operation is
performed.
(emphasis added).
This question already has answers here:
I can use more memory than how much I've allocated with malloc(), why?
(17 answers)
Closed 9 years ago.
As I know that malloc allocate a specific number of bytes in the memory. However I am trying to use it and I allocate 4 bytes but it gives me NO error when I try to store more than 4 (up to 200 integers) elements in the array!! So in my code I don't need to use realloc!! I'm using Linux by the way. Finally I will pleased to hear any advice from you ... thanks in advance.
tmp.h :
#ifndef TMP_H
#define TMP_H
#define MAXLENGTH 4
#define GROWFACTOR 1.5
typedef struct stVector
{
int *vec;
int length;
int maxLength;
}Vector;
Vector newEmptyVector();
void addElement(Vector *vec, int elt);
#endif
tmp.c :
#include "stdio.h"
#include "stdlib.h"
#include "tmp.h"
Vector newEmptyVector()
{
Vector vec;
vec.vec = (int*) malloc(0);
printf("Allocating %d bytes\n", sizeof(int)*MAXLENGTH );
vec.length = 0;
vec.maxLength = MAXLENGTH;
return vec;
}
void addElement(Vector *vec, int elt)
{
/*if(vec->length == vec->maxLength)
{
vec->vec = (int*)realloc(vec->vec,sizeof(int)* vec->maxLength * GROWFACTOR);
vec->maxLength = vec->maxLength * GROWFACTOR;
}*/
vec->vec[vec->length++] = elt;
}
main.c :
#include"tmp.h"
int main(int argc, char const *argv[])
{
Vector vector = newEmptyVector();
printf("The length is %i and maxlength is ` `%i\n",vector.length,vector.maxLength);
addElement(&vector,5);
addElement(&vector,3);
addElement(&vector,1);
addElement(&vector,7);
printf("The length is %i and maxlength is ` `%i\n",vector.length,vector.maxLength);
addElement(&vector,51);
printf("The length is %i and maxlength is %i\n",vector.length,vector.maxLength);
for (int i = 0; i < 200; ++i)
{
addElement(&vector,i);
printf("The length is %i and maxlength is %i\n" ,vector.length, vector.maxLength);
}
return 0;
}
Using memory you haven't allocated invokes undefined behavior. Don't do that. In all likelyhood, Linux has give your program a page of memory, and you haven't overrun that yet. If you touch memory not allocated to your program the OS should cause your program to segfault. But it's possible that any other mallocing you do will also use parts of that page, and you'll end up corrupting your data.
Not having runtime checks for overrunning buffers is part of what makes C fast, but it puts more on the programmer not to do dumb things.
The fact that (simply because there is no bound checking in C) no error is raised does not mean that you can safely use memory outside requested bounds. You were lucky not to cause a segmentation fault, you have just fallen into a memory region that is not claimed by your malloc (let's say, it's not yours).
You can write there, but there is no guarantee that you won't be overwriting memory assigned to another malloc or, conversely, that the "extra" part will not be allocated to some other malloc. In your case, the memory region you are writing into appears not to be claimed (yet).
Regarding your specific issue:, I allocate 4 bytes but it gives me NO error when I try to store more than 4.
Keep in mind, something like:
int *anyVar = (int)malloc(0);
anyVar[0] = 12; //Will eventually invoke undefined behavior.
writing to memory you do not own will eventually invoke undefined behavior. The bad thing is that your results can seem good, and even repeatable for many runs of the code. But at some point, your code will fail.
This is how you should allocate: (by the way)
int numIntsInArray = 100;
int *anyVar = malloc(sizeof(int)*numIntsInArray);//note:do not cast output of malloc
anyVar[0] = 1;//first element of anyVar
anyVar[99] = 1000;//last element of anyVar
Do not forget to free all memory:
free(anyVar);
Other examples of undefined behavior in C & C++:
The examples of bad code below can be done, and you will likely get no compiler warnings, and may even get
expected results during run-time, but with this code, nothing is guaranteed. (exception: good examples)
char * p = "string"; // Badly formed C++11, deprecated C++98/C++03
p[0] = 'X'; // undefined behavior
Create an array instead:
char p[] = "string"; // Good
p[0] = 'X';
C++, you can create/use a standard string like this:
std::string s = "string"; // Good
s[0] = 'X';
Division by zero results in undefined behavior:
int x = 1;
return x / 0; // undefined behavior
Some pointer operations may lead to undefined behavior:
int arr[4] = {0, 1, 2, 3};
int* p = arr + 5; // undefined behavior
Leaving a non-void function without returning a value
int func(void)
{
//undefined behavior
}
Unspecified or implementation-defined behavior:
printf("%d %d\n", ++n, power(2, n)); //Bad
i = ++i + 1; //Bad
i = i + 1; // Okay
I've got this code:
int main() {
int i=0, n=0;
char sep=NULL;
double **aero=(double**)malloc(sizeof(double*));
*aero=(double*)malloc(2*sizeof(double));
printf("Zadejte souradnice:\n");
while (1) {
aero=(double**)realloc(aero,(n+1)*sizeof(double*));
for (i=0; i<n+1; i++) {
aero[i]=(double*)realloc(aero[i],2*sizeof(double));
}
if ((scanf("[%lf,%lf]%c",&aero[n][0],&aero[n][1],&sep))==3 && (sep=='\n' || sep==' ')) {
n++;
continue;
} else if (!feof(stdin)) {
printf("Nespravny vstup.\n");
freeArray2D(aero,n);
return 0;
}
break;
}
}
It works fine, but I can scanf coordinates (in format: [x,y]) only 19 times. Then it shows me Segmentation fault (core dumped). I use Linux compiler gcc -Wall -pedantic main.c -lm I have no idea, where is the problem. Thanks for any help.
You never assign a fresh malloced buffer to aero[1], but pass the garbage in there to realloc. Maybe you expected the realloc for aero to zero-initalize the memory?
In aero[i]=(double*)realloc(aero[i],2*sizeof(double)), if i == n, then aero[i] is uninitialzed. You should not call realloc on an uninitialized pointer.
Your specific problem is that you realloc a pointer, aero[n], that was never malloced in the first place (and is not necessarily NULL). That's a recipe for disaster.
You also have another issue though it's more an unnecessary-work problem than a fatal flaw. You are re-allocating every single aero[] variable in the loop when they're not actually changing in content or size. It appears to me that all you need to do in the loop is simply increase the size of the first level of memory aero and allocate memory for its new element:
while (1) {
aero = realloc (aero, (n+1) * sizeof (double*));
aero[n] = malloc (2 * sizeof (double));
:
You'll notice I've removed the casting of the malloc return values. This casting is ill-advised in C as it can hide certain subtle errors. C is perfectly capable of converting the void* return values into any other pointer type implicitly.
And, of course, you should never assume that your memory allocations will work - I'd be checking the return values for NULL and exiting immediately if I found one.
The only other issue I had (other than my inability to read Czech of course) was the setting of the char sep to NULL. NULL is usually reserved for pointers rather than characters so it looks more sensible if you initialise it to \0.