I need to write in a variable allocated through a function. I found a lot of threads discussing this, such as Allocating a pointer by passing it through two functions and How to use realloc in a function in C, which helped me fixing some issues, but one remains and I can't find the cause.
Consider the following code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
void foo(uint64_t** m)
{
*m = realloc(*m, sizeof(uint64_t) * 4);
*m[0] = (uint64_t)1;
//*m[1] = (uint64_t)2; // create a segfault and crash right here, not at the print later
}
int main()
{
uint64_t* memory = NULL;
foo(&memory);
for(int i = 0; i < 4; i++)
printf("%d = %ld\n", i, memory[i]);
return 0;
}
I send the address of memory to foo, which takes a double pointer as an argument so it can modify the variable. The realloc function need a size in bytes, so I make sure to ask for 4 * sizeof(uint64_t) to have enough space to write 4 64-bits int. (The realloc is needed, I don't need malloc).
I can then write in m[0] without issue. But if I write in m[1], the program crashes.
What did I do wrong here ?
Related
I saw the following code:
#include <stdlib.h>
void foo(char n)
{
int (*vals)[n] = malloc(sizeof(int[n]));
for (int i = 0; i < n; ++i)
(*vals)[i] = i;
free(vals);
}
int main(int argc, char **argv)
{
foo(*(argv[1]));
return 0;
}
This lines makes me very uncomfortable:
free(vals);
vals is a pointer pointing to an array. This looks right, but I just have a difficult time internalizing it, I do not know why.
I am more used to the following style:
int *p = (int*)malloc(n * sizeof(int));
......
free(p);
In this code, p is a pointer pointing to the start of a memory region for some integers, the malloc and free are symmetric in that they both work on a pointer type; yet the original code has malloc() working on a pointer to an array and free() a pointer.
Out of curiosity, I modified the original code:
free(vals); ==> free(*vals);
I was expecting this change will fail at compiler, the reason is *vals is an array now. But gcc is fine and valgrind does not complain memory leak.
I know C has a thing called array degenerates to pointer at function call. But I just cannot internalize this stuff. Sorry writing so long to describe a problem, wish you could see my struggle. Is there a definitive doc/stackoverflow/blog to clear this up - best C99 or later?
Thanks!
writing free(*vals); is same as writing free(vals);
edited your code to clear that a little bit
#include <stdlib.h>
#include <stdio.h>
void foo(char n)
{
int (*vals)[n] = malloc(sizeof(int[n]));
for (int i = 0; i < n; ++i)
(*vals)[i] = i;
printf("*val is %p\n", *vals);
printf("val is %p\n", vals);
printf("&val is %p\n", &vals);
free(vals);
}
int main()
{
foo(10);
return 0;
}
and this is the output:
*val is 0000018190365d50
val is 0000018190365d50
&val is 0000005d9dbff7b8
note that vals is Array pointer which means that its base type is an array of n integers where the pointer val is created in that stack and points to the whole array, not the first element only and that array is created in the heap, to illustrate, look at the following graph:
so for example if you write:
printf("val is %p\n", vals);
printf("val+1 is %p\n", vals+1);
the output will be :
val is 00000207ef0c5d50
val+1 is 00000207ef0c5d78
note the difference between the 2 is about 40 bytes as val points to the whole array not only one element as in case of int *p = (int*)malloc(n * sizeof(int));
note that when I say it points to the whole array, I also mean it points to the base address of the array.
in case of *Vals, look at the next graph:
*Vals is just an address of the first element of the array which is by the way is same as the base address of the array.
refer to free() manual, they said:
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.
and what does malloc() function return ?
it returns the base address of your reserved space in heap, so writing free(vals); is same as writing free(vals);
This codes uses dynamic VLA.
I think that it may be easier to understand if the code is reformulated with a typedef.
void foo(char n)
{
typedef int T[n];
T *vals = malloc(sizeof(T));
...
free(vals);
}
Now it looks like a tivial use of a single dynamic object.
To access elements of an array first the pointer has to be dereferenced *vals forming an array, which decays to int* pointer suitable for [] operator.
I'm trying to create a graph with 264346 positions. Would you know why calloc when it reaches 26,000 positions it stops generating memory addresses (ex: 89413216) and starts generating zeros (0) and then all the processes on my computer crash?
The calloc function should generate zeros but not at this position on my code.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <string.h>
#include <limits.h>
int maxV;
struct grafo {
int NumTotalVertices;
int NumVertices;
int NumArestas;
int **p;
};
typedef struct grafo MGrafo;
MGrafo* Aloca_grafo(int NVertices);
int main(){
MGrafo *MatrizGrafo;
MatrizGrafo = Aloca_grafo(264346);
return 0;
}
MGrafo* Aloca_grafo(int NVertices) {
int i, k;
MGrafo *Grafo ;
Grafo = (MGrafo*) malloc(sizeof(MGrafo));
Grafo->p = (int **) malloc(NVertices*sizeof(int*));
for(i=0; i<NVertices+1; i++){
Grafo->p[i] = (int*) calloc(NVertices,sizeof(int));// error at this point
//printf("%d - (%d)\n", i, Grafo->p[i]); // see impression
}
printf("%d - (%d)\n", i, Grafo->p[i]);
Grafo->NumTotalVertices = NVertices;
Grafo->NumArestas = 0;
Grafo->NumVertices = 0;
return Grafo;
}
You surely dont mean what you have in your code
Grafo = (MGrafo*)malloc(sizeof(MGrafo));
Grafo->p = (int**)malloc(NVertices * sizeof(int*)); <<<<=== 264000 int pointers
for (i = 0; i < NVertices + 1; i++) { <<<<< for each of those 264000 int pointers
Grafo->p[i] = (int*)calloc(NVertices, sizeof(int)); <<<<<=== allocate 264000 ints
I ran this on my machine
its fans turned on, meaning it was trying very very hard
after the inner loop got to only 32000 it had already allocated 33 gb of memory
I think you only need to allocate one set of integers, since I cant tell what you are trying to do it hard to know which to remove, but this is creating a 2d array 264000 by 264000 which is huge (~70billion = ~280gb of memory), surely you dont mean that
OK taking a comment from below, maybe you do mean it
If this is what you really want then you are going to need a very chunky computer and a lot of time.
Plus you are definitely going to have to test the return from those calloc and malloc calls to make sure that every alloc works.
A lot of the time you will see answers on SO saying 'check the return from malloc' but in fact most modern OS with modern hardware will rarely fail memory allocations. But here you are pushing the edge, test every one.
'Generating zeros' is how calloc tells you it failed.
https://linux.die.net/man/3/calloc
Return Value
The malloc() and calloc() functions return a pointer to the allocated memory that is suitably aligned for any kind of variable. On error, these functions return NULL. NULL may also be returned by a successful call to malloc() with a size of zero, or by a successful call to calloc() with nmemb or size equal to zero.
Here is the code I'm using:
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr;
int sz = 100000;
arr = (int *)malloc(sz * sizeof(int));
int i;
for (i = 0; i < sz; ++i) {
if (arr[i] != 0) {
printf("OK\n");
break;
}
}
free(arr);
return 0;
}
The program doesn't print OK. malloc isn't supposed to initialize the allocated memory to zero. Why is this happening?
malloc isn't supposed to initialize the allocated memory to zero. Why is this happening?
This is how it was designed more than 40 years ago.
But, at the same time, the calloc() function was created that initializes the allocated memory to zero and it's the recommended way to allocate memory for arrays.
The line:
arr = (int *)malloc(sz * sizeof(int));
Should read:
arr = calloc(sz, sizeof(int));
If you are learning C from an old book it teaches you to always cast the value returned by malloc() or calloc() (a void *) to the type of the variable you assign the value to (int * in your case). This is obsolete, if the value returned by malloc() or calloc() is directly assigned to a variable, the modern versions of C do not need that cast any more.
The man page of malloc says:
The malloc() function allocates size bytes and returns a pointer to
the allocated memory. The memory is not initialized. If size is 0,
then malloc() returns either NULL, or a unique pointer value that can
later be successfully passed to free().
So malloc() returns uninitialized memory, the contents of which is indeterminate.
if (arr[i] != 0)
In your program, You have tried to access the content of a memory block, which is invoked undefined behavior.
malloc isn't supposed to initialize the allocated memory to zero.
Memory allocated by malloc is uninitialised. Value at these locations are indeterminate. In this case accessing that memory can result in an undefined behavior if the value at that location is to be trap representation for the type.
n1570-ยง6.2.6.1 (p5):
Certain object representations need not represent a value of the object type. If the stored value of an object has such a representation and is read by an lvalue expression that does not have character type, the behavior is undefined. [...]
and footnote says:
Thus, an automatic variable can be initialized to a trap representation without causing undefined behavior, but the value of the variable cannot be used until a proper value is stored in it.
Nothing good can be expected if the behavior is undefined. You may or may not get expected result.
From the C Standard 7.22.3.4:
Synopsis
#include <stdlib.h>
void *malloc(size_t size);
Description
The malloc function allocates space for an object whose size is
specified by size and whose value is indeterminate.
The value is indeterminate. So, every compiler is free to behave how it wants. For example, in Microsoft Visual C++, in Debug mode, the area of allocated memory by malloc() is all set to 0xCDCDCDCD and when in Release mode it is random. In modern versions of GCC, it is set to 0x000000 if you don't enable code optimizations, and random otherwise. I don't know about other compilers, but you get the idea.
void *malloc(size_t size) is just supposed to keep aside the specified amount of space. That's all. There is no guarantee as to what will be present in that space.
Quoted from the man pages:
The malloc() function allocates size bytes and returns a pointer to
the allocated memory. The memory is not initialized. If size is 0,
then malloc() returns either NULL, or a unique pointer value that can
later be successfully passed to free().
Apart from calloc() you can use the memset() function to zero out a block of memory.
The first time you call malloc(3), it asks to the operating system to get memory for the heap space.
For security reasons, the unix/linux kernel (and many other operating systems) in general zeroes the page contents that is to be given to a process, so no process can access that memory's previous contents and do nasty things with it (like searching for old passwords, or similar things).
If you do several allocations and deallocations of memory, when the malloc module reuses the previous memory, you'll see garbage coming from malloc(3).
Zero's are assigned to page contents at first time in linux kernel.
Below program explains the memory initialisation difference in malloc and calloc:
#include<stdio.h>
#include<stdlib.h>
#define SIZE 5
int main(void) {
int *mal = (int*)malloc(SIZE*sizeof(int));
int *cal = (int*)calloc(SIZE, sizeof(int));
mal[4] = cal[4] = 100;
free(mal); free(cal);
mal = (int*)malloc(SIZE*sizeof(int));
cal = (int*)calloc(SIZE, sizeof(int));
for(int i=0; i<SIZE; i++) {
printf("mall[%d] = %d\n", i, mal[i]);
}
for(int i=0; i<SIZE; i++) {
printf("call[%d] = %d\n", i, cal[i]);
}
}
I use malloc to allocate everything from the heap(dynamic memory) while i should use calloc instead nowaday , and memset is great for filling you memory segment with any chosen character.
Compile and work great with GCC:
#include <stdio.h>
#include <stdlib.h>
#include <mem.h>
int main()
{
int *arr;
int sz = 100000;
arr = (int *)malloc(sz * sizeof(int));
memset(arr, 0, sz*sizeof(int) );
int i;
for (i = 0; i < sz; ++i) {
if (arr[i] != 0) {
printf("OK\n");
break;
}
}
free(arr);
return 0;
}
ref: http://www.cplusplus.com/reference/cstring/memset/
well, the value is not initialized in malloc.
And it does print "OK" in VS Code.
so in VS Code, the output is : "OK" followed by a garbage value.
in a web based compiler (here's the link : https://www.programiz.com/c-programming/online-compiler/ ),
the output was
"LOL" followed by '0'
so some compilers do initialize the value..but actually the value in malloc is not intialized. so it will return a garbage value when printed as in the above example in VS Code.
int main()
{
int *arr;
int sz = 100000;
arr = (int *)malloc(sz * sizeof(int));
int i;
for (i = 0; i < sz; i++)
{
if (arr[i] != 0)
{
printf("OK\n");
break;
}
else
{
printf("LOL \n");
break;
}
}
printf("%d", arr[0]);
free(arr);
I am writing a ring buffer with C.
I am stuck on freeing the memory in the end.
The code compiles well, but the result shows circBuf_free function fails to free the allocated memory.
The relevant codes are:
#include <stdint.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //memcpy
#define kNumPointsInMyBuffer 16
#define initialSize 10
typedef struct CircBuf_t //struct name CircBuf_t
{
uint32_t *buffer;
int head; // keep track the newest data
int tail; // keep track the oldest data
int maxLen; // maximum number of items in the buffer
}circBuf_t; //type name circBuf_t
// initialize the circular buffer
void circBuf_init(circBuf_t *c, const int maxLen, int sz)
{
c->buffer = malloc(maxLen * sz);
c->maxLen = maxLen;
if(c->buffer == NULL)
printf("Buffer initialization fails\n");
c->head = 0;
c->tail = 0;
}
/* free the memory, free c->buffer first, then c*/
void circBuf_free(circBuf_t *c){
free(c->buffer);
free(c);
}
int main(){
// initilize ring Buffer
const int maxLen = kNumPointsInMyBuffer;
// original src
int src[1024] = {};
int i =0;
for(i=0; i<1024; i++){
src[i] = i;
}
//data
uint32_t data[1024];
memcpy(data, src, 1024);
printf("\nThe size of the uint32_t data array is %lu\n", sizeof(data));
int sz = sizeof(*data);
circBuf_t *cb;
cb = malloc(sizeof(circBuf_t));
circBuf_init(cb, maxLen, sz);
assert(cb);
printf("cb's value is %p\n", cb);
circBuf_free(cb);
printf("cb's value is %p\n", cb);
assert(!cb);
return 0;
}
Result:
cb's value is 0x1266010
cb's value is 0x1266010
a.out: sample.c:73: main: Assertion `!cb' failed.
Aborted (core dumped)
The address of the pointer to the structure is the same.
Need help!
When you call free, the memory pointed to by the passed pointer is
freed, but the value of the pointer in the caller probably remains
unchanged, because C's pass-by-value semantics mean that called
functions never permanently change the values of their arguments. (See
also question 4.8.)
A pointer value which has been freed is, strictly speaking, invalid,
and any use of it, even if it is not dereferenced (i.e. even if the
use of it is a seemingly innocuous assignment or comparison), can
theoretically lead to trouble. (We can probably assume that as a
quality of implementation issue, most implementations will not go out
of their way to generate exceptions for innocuous uses of invalid
pointers, but the Standard is clear in saying that nothing is
guaranteed, and there are system architectures for which such
exceptions would be quite natural.)
When pointer variables (or fields within structures) are repeatedly
allocated and freed within a program, it is often useful to set them
to NULL immediately after freeing them, to explicitly record their
state.
Source :
http://c-faq.com/malloc/ptrafterfree.html
if is it possible run-time bad pointer exception in C language?.
I am using below compiler.
Note : Microsoft Visual C++ Compiler
Sample Programs Below.
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <Windef.h>
typedef struct tagTest{
int i;
char *str;
} Test,
FAR *LPTest,
FAR **LLPTEST;
extern LLPTEST m;
int main()
{
int i;
LLPTEST m = NULL;
m = (LLPTEST)malloc(sizeof(LLPTEST));
// Here We Check m[0] memory allocated or not ?
// example: if(m[0]), or if(m[0]->i) any other idea. here m[0] is CXX0030 error expression cannot be evaluated.
/* allocate memory */
for(i=0; i<10; i++)
{
m[i] = (LPTest) malloc(sizeof(Test));
m[i]->i = i;
m[i]->str = (char*) malloc(10*sizeof(char));
m[i]->str = "Test";
}
return 0;
}
No. C doesn't support exceptions, so there's nothing to catch. What you're seeing isn't a "bad pointer exception," it's a memory access error -- there is no way to recover from it.
You have several problems in your code. Here's a list of some of them:
Don't cast the return of malloc
For m you allocate sizeof(LLPTEST) bytes, but you should really allocate sizeof(LPTest)
Continuing the previous point, you only allocate one pointer, so only m[0] is valid, all other indexes will cause you to write out of bounds. You should do e.g.
m = malloc(sizeof(LPTest) * 10);
This point is the cause of your problems, as it causes undefined behavior
You allocate memory for m[i]->str, but then you overwrite that pointer with a pointer to a string literal, thereby loosing the pointer to the allocated memory (i.e. you have a memory leak)
Continuing the previous point, because m[i]->str now points to a string literal, and not something you allocated yourself, you can not free this pointer
No error checking, remember that malloc can fail
If you don't know how many items you need to allocate for m beforehand, you can use realloc to reallocate with a larger size.
Some exceptions can catch MSVC is to extend the syntax.
#include <windows.h>
#include <stdio.h>
typedef struct tagTest{
int i;
char *str;
} Test;
int main(){
Test *m;
//m = malloc(sizeof(Test));//it can be avoided by examining whether NULL simply.
m = NULL;//malloc is unable to allocate memory
__try{
m->i = 0;//exception occurs
m->str = "Test";
}
__except(EXCEPTION_EXECUTE_HANDLER){
if(EXCEPTION_ACCESS_VIOLATION==GetExceptionCode())
puts("ACCESS VIOLATION");
puts("EXCEPTION OCCURRED");
}
}