Malloc for struct [duplicate] - c

This question already has answers here:
Using sizeof with a dynamically allocated array
(5 answers)
Closed 5 years ago.
I´m working on my program, that loads data from external .txt file - it is structure of 3 integers. Now Im struggling with function that allocates memory. I want to allocate memory for structure of 9 members (108 bytes).
My main program was too large to mess with so I created a smaller program to help me more easily figure out what is going on. Previous questions I went through seemed too complicated and unclear to me, that´s why I made my own.
Id like to know why the third printf, prints 4 and how to correctly allocate required memory (108 bytes)
Glad for any advice
#include <stdio.h>
#include <math.h>
int main(){
int object_counter = 9;
typedef struct myStruct {
int name;
int age;
int height;
} myStruct;
myStruct* dynamicStruct;
dynamicStruct = malloc(object_counter*sizeof(myStruct));
if (dynamicStruct == NULL) {
printf("ERROR\n");
return (-1);
} else {
printf("SUCCESS\n");
}
printf("Size is: %lu\n", sizeof(myStruct)); // prints 12, thats 3 times int, OK
printf("Size is: %lu\n", object_counter*sizeof(struct myStruct)); // prints 108, obviously 9 times 4 bytes
printf("Size is: %lu\n", sizeof(dynamicStruct)); // prints 4 ?? (expected 108)
return 0;
}

The sizeof any pointer is constant (8 bytes on my Linux/x86-64 system, which is also the sizeof(uintptr_t), etc....). It is unrelated to the runtime size of the pointed memory zone. In other words, the sizeof operator always gives a compile-time constant (except for VLAs).
You practically need to keep elsewhere the allocated size of a malloc-ed pointer. For example, you could keep the pointer value in one variable, and its allocated size in another variable.
You could consider an abstract data type (using flexible array members) approach like here.

Related

Allocating a large array on the stack in C [duplicate]

This question already has answers here:
Getting a stack overflow exception when declaring a large array
(8 answers)
Closed 3 years ago.
I have the following program:
#include <stdio.h>
#include <sys/resource.h>
int main()
{
// Anything over ~8MB fails
short int big[4000000];
printf("%lu\n", sizeof(big));
}
ulimit shows that I have unlimited memory available to the program. However, if I try and allocate more memory I get an error:
short int big[6000000];
$ gcc main.c -o main.out && ./main.out
Segmentation fault: 11
Is there anything I need to change within the C program so that I can allocate, for example a 1GB array?
You're statically allocating an array on the stack, this means that the compiler will write code to reserve that space, and when your main() is called, it will try to move the stack pointer way out of the available mapped stack area for your program. Touching the stack would then cause a segmentation fault, which is what you see.
You could increase the stack size, but it's not that simple nor portable, and in general allocating such a large array on the stack is bad practice and should be avoided. To handle such a big array, you should dynamically allocate it, using for example malloc().
Here's a working example:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
short int *big;
big = malloc(6000000 * sizeof(short int));
if (big == NULL) {
fputs("Failed to allocate memory!\n", stderr);
return 1;
}
// Do whatever...
free(big);
return 0;
}
Also, remember that you cannot use sizeof() in this case since big is a dynamically allocated array (sizeof(big) would yield the size of the pointer, not the real size of the array). This is because sizeof() is a compile-time operator and can only help you if the size is known at compile time. In this case, it is not, since the space is allocated at runtime.
If you want to know the size of that array, you can simply calculate it with a multiplication:
short int *big;
const size_t big_size = 6000000ULL * sizeof(short int);
printf("Size: %zu\n", big_size);
big = malloc(big_size);
// ...
You can't statistically declare any array with that big size. It causes the program stack to overflow. What you need is to declare memory dynamically. And here linked list can serve your purpose.
#include <stdio.h>
#include <sys/resource.h>
int main()
{
// allocate the memory you need
short int* big = (short int*)malloc(6000000 * sizeof(short));
if(big)
{
printf("alloc all good\n");
// to free memory
free(big);
}
else
{
printf("alloc failed\n");
}
}
You should use dynamic memory allocation instead of statically defining an array for allocating 1GB of data.This link will help you learn the difference

C creating a struct array beyond certain size causes a crash [duplicate]

This question already has answers here:
Getting a stack overflow exception when declaring a large array
(8 answers)
Closed 5 years ago.
Hi all I am really new to C (just started this week), and want to make sure that I am not looking down the wrong rabbit home and hoping to perhaps get pointed to the right rabbit hole.
I create a struct:
#define MAX 64
#define ARRAY_SIZE 2048
struct object {
int q, c, p;
char name[MAX]; //Stores string up to 63 characters
char arr[ARRAY_SIZE][MAX]; // Creates an array of 2048 cells with string of length 63 max
};
int main(){
...
...
int variable = 30;
struct object l[variable]; //This is where the crash happens. But only when either variable is too large (for instance works on 15 just fine, but anything over 20 it crashes), or when Array_SIZE is too larger, for instance works fine with 1024 but 2048 crashes.
...
...
}
The error I get on crash is the following: Process returned -1073741571 (0xC00000FD) in the cmd window. And the following in the debugger in the IDE:
Program received signal SIGSEGV, Segmentation fault.
[Inferior 1 (process 12120) exited with code 030000000375]
Am I doing something obviously wrong with how I declare an array of structs? Why would large numbers not work but lower numebrs work?
Does the above error indicate I am accessing something out of bounds somewhere? Ive been up and down the code and cant seem to find any reason why larger numbers dont work and lower ones do. My memory footprint doesnt seem to be the issue, just a few megs of memory.
I need help with what to look for (I cant find any instances of accessing anything out of bounds, so I get the feeling Im not chasing the right rabbit and need to look for something else)? Or maybe Im doing something illegal for C without knowing it?
I think your program crashes because you statically allocate too much memory on the stack.
Try using the malloc or calloc function. It dynamically allocates memory on the heap instead e.g. :
struct object *l = malloc(variable*sizeof(struct object));
Don't forget to free it afterwards using the free function.
free(l);
You have a memory size problem, try to increase the memory size for your program.
And if you want to use big array size and so allocate a lot of memory, you shouldn't allocate statically but dynamically.
So you should use malloc
typedef struct object {
int q, c, p;
char name[MAX]; //Stores string up to 63 characters
char arr[ARRAY_SIZE][MAX];
} myObject ;
int variable = 30;
myObject *l = malloc(sizeof(myObject) * variable);
I do not advice you to declare an array of 2048 statically, so you should initiate your struct with a function.
typedef struct object {
int q, c, p;
char name[MAX]; //Stores string up to 63 characters
char *arr[MAX];
} myObject ;
myObject *createNewObject() {
myObject *toReturn = malloc(sizeof(myObject) * variable);
if (toReturn == NULL)
return NULL;
toReturn->arr = malloc(sizeof(char) * ARRAY_SIZE);
return (toReturn);
}
void freeMyObject(myObject *objectToFree)
{
if (objectToFree && objectToFree->arr =! NULL)
free(objectToFree->arr)
if (objectToFree)
free(objectToFree)
}
void main()
{
myObject *myNewObj = createNewObject()
// You can do some stuff with myNewObj but always verify the pointers
freeMyObject(myNewObj);
}
You should also debug with valgrind when you works with malloc, so you don't have memory loss or problems.
Hope I helped
Well the problem you had is - you have used automatic memory allocation. Due to constraint of size of automatic storage your program crashed - you asked for more than you should.
So what is the solution?
Static memory allocation:
Solution being
static struct object l[variable];
Dynamic memory allocation
struct object *ptr = malloc( sizeof *ptr * variable);
The storage of these allocation is different from automatic variables - so free from the size constraint . In this case you have to free the dynamically allocated memory. That's why you will get around the problem you have.
Statically allocate is not a confusion free term. All these types of variable will have different scope - lifetime. Standard never mentions about stack or heap . It is the implementation that follow these to store automatically allocated memory and dynamically allocated memory.

C realloc not changing array

So, to start off I've already looked at a few questions including this one and none of them seem to help.
I'm simply trying to write a function that extends the size of an array using realloc().
My code currently looks like this:
unsigned char *xtnd = malloc(4);
xtndc(&xtnd, 4);
// sizeof(*xtnd) should now be 8
void xtndc ( unsigned char ** bytesRef , uint8_t count ) {
*bytesRef = realloc(*bytesRef, (sizeof(**bytesRef)) + count);
}
But no matter what I do it seems that the size of xtnd is always 4. After running xtndc() on it it should now be 8 bytes long.
Any suggestions?
The type of **bytesRef is unsigned char, so sizeof(**bytesRef) is 1. sizeof doesn't keep track of dynamic allocations, it's a compile time tool that gives you the size of a type, in this case unsigned char.
You have to keep track of the array size manually to calculate the new required size.
Your program does in fact change the size of the memory block. It changes the size of your original memory block from 4 bytes to 5 bytes. It changes to 5 bytes because you are essentially doing sizeof(unsigned char) + 4 which 1 + 4 = 5. If you want to double the size instead, do count*sizeof(unsigned char) + count. There are two points to be noted here:
The sizeof function returns the size of the data type, not the size of the allocated bytes. There is no way to know the size of the dynamically allocated memory.
The function realloc (and malloc and calloc as well) is not always guaranteed to return the requested reallocation. It may or may not succeed all the time.
I fixed the problem with the following code.
typedef struct CArrPtr {
unsigned char* ptr;
size_t size;
} CArrPtr;
void xtndc ( CArrPtr *bytesRef, uint8_t count );
. . .
CArrPtr xtnd = { .ptr = malloc(4), .size = 4 };
xtndc( &xtnd, 4 );
// xtnd.size is now 8 bytes
. . .
void xtndc ( CArrPtr *bytesRef, uint8_t count ) {
unsigned char *nptr;
if((nptr = realloc(bytesRef->ptr, bytesRef->size + count)) != 0)
{
bytesRef->ptr = nptr;
bytesRef->size = bytesRef->size + count;
}
}
As I am somewhat new to C, what I learned from this is that malloc specifically creates a pointer to a memory block, but you have no direct access to information about the memory block. Instead, you must store the size of the array that you created with malloc somewhere as well.
Since in the past I'd been initializing arrays with unsigned char arr[size]; and then using sizeof on it, I was under the impression that sizeof returned the size of the array, which is of course wrong as it gives you the size of a type.
Glad I could learn something from this.
sizeof is used to calculate size of data type or array. Pointer and array are very similar, but they are different things. For int *ap, sizeof(ap) will return 4 on x86, sizeof(*ap) will return 4; for int a[10], sizeof(a) will return 40.
sizeof expression is processed at compile time, so it will be a constant written into the executable file before you run the program.
malloc and realloc don't maintain size.
If realloc succeeds, it will reallocate the requested size. So you don't need to check the size after realloc returns, but you should check the return value of realloc to ensure that realloc succeeds.

Formal malloc to use realloc later [duplicate]

This question already has answers here:
Initially mallocate 0 elements to later reallocate and measure size
(2 answers)
Closed 6 years ago.
Below code is just an example which I use to come to the point later:
/* Extract digits from an integer and store in an array in reverse order*/
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int oct=316;
int* array=malloc(0*sizeof(int*)); //Step 1
int* temp;
size_t size=0;
while(oct/10>0 || oct%10>0){
temp=realloc(array,++size*sizeof(int)); // Step2 requires Step1
if(temp==NULL){
printf("Can't reallocate memory");
exit(-1);
}
else{
array=temp;
}
array[size-1]=oct%10;
oct/=10;
}
for(int i=0;i<size;i++)
printf("%d\n",array[i]);
return 0;
}
The realloc reference [1] states :
Reallocates the given area of memory. It must be previously allocated
by malloc(), calloc(), realloc()...
Initially I compiled the code without step1 and on running it I got a segmentation fault. Then I included step1, now the code compiles fine. I don't want to allocate some space without finding an integer to store so I have used a size of zero with malloc. However malloc reference [2] states :
If size is zero, the return value depends on the particular library
implementation (it may or may not be a null pointer), but the returned
pointer shall not be dereferenced.
Now, I doubt my implementation is portable. How can I work around this issue?
I tried doing int* array=NULL; but I got a segmentation fault.
You can initiate array to NULL. In the man page for realloc(void *ptr, size_t size) you can read:
If ptr is NULL, then the call is equivalent to malloc(size)
Moreover realloc does not change its parameter. It returns pointer to newly allocated/reallocated space. So, for reallocating you shall use a code like:
array = realloc(array,(++size)*sizeof(int));
if (array == NULL) { some error; }

calculating array sizes in C

I have a macro for calculating array sizes in my C code:
#define sizearray(a) (sizeof(a) / sizeof((a)[0]))
When I test it, it works fine for statically defined arrays, but not so for dynamically defined arrays (see below). Not sure I understand why this is the case. Is there any way of calculating the size of an array allocated on the heap?
/* test sizearray macro */
void testSIZEARRAY(void)
{
/* test case for statically defined array */
int a[5] = {0,0,0,0,0};
assert(sizearray(a) == 5);
/* test case for dynamically defined array */
int *b;
b = calloc(5, sizeof(int));
assert(sizearray(b) == 5);
free(b);
}
The answer is no, there is no standard way to get the size of a dynamically allocated array.For all practical purposes, you have to keep track it yourself.
However, there are some compiler-specific methods that do that:
Windows (Visual Studio): _msize()
GCC: msize() Can't find it in the GCC docs...
int *b;
...
assert(sizearray(b) == 5);
A pointer is not an array. b is declared as pointer to int
Here
sizeof b == sizeof (int *)
The sizeof operator applied to an object of a pointer type is the same as the size of the pointer type and is not equivalent to the size of the allocated array.
To know the size of your allocated array object you have to inspect what was allocated. In your example you allocate an object of 5 int, so the size of your array is:
5 * sizeof (int)
(or equivalent, 5 * sizeof *b)
There is no way to calculate the size of an array if you only have a pointer to its first element (as you do in the above case with int *b). You need to either store the array size separately and use it together with your pointer, or somehow mark the end of the array. The latter solution is used in character arrays, which are usually null-terminated (have \0 as their last character). In this case, you can calculate the size by looping till you encounter such a termination character.
The followng is bad advice, do not do that.
To get the memory allocated by the current glibc's malloc() (et al) you could try the following:
#include <stdlib.h>
#include <stdio.h>
#define GLIB_MSIZE_T size_t /* We need to have a four byte unsigned integer type
here. */
#define GLIB_MSIZE(p) \
*((GLIB_MSIZE_T*) (((char*) p) - sizeof(GLIB_MSIZE_T)))
int main(int iArgC, char ** ppszArgV)
{
if (1 >= iArgC)
{
fprintf(stderr, "usage: %s <bytes to allocate>\n", ppszArgV[0]);
return EXIT_FAILURE;
}
{
/* This conversion uing 'atol()' only works up until to a certain size
of the integer represented by 'ppszArgV[1]'. */
size_t size = atol(ppszArgV[1]);
void * pv = malloc(size);
if (!pv)
{
fprintf(stderr, "Allocation of %u bytes failed.\n", size);
return EXIT_FAILURE;
}
printf("Asked for %u bytes, got %u bytes.\n", size, GLIB_MSIZE(pv));
}
return EXIT_SUCCESS;
}
Besides the fact one indeed could get the amount of memory allocated, the interesting thing to see when paying with this code is, that in most of the cases more then the size of memory requested is assigned.
Anyhow, the latter makes it unsafe trying to pull information from this on the exact size originally requested.

Resources