I'm trying to reallocate memory for an pointers vector, originally the vector is:
Album* albuns
Where Album is a struct;
I created a function passing the adress of type albuns and the total number of albuns as arguments:
void AddAlbum (int* n_albuns, Album** albuns);
I wanted to reallocate memory for albuns so it could receive another pointer to album, so i did:
int aux = (*n_albuns) + 1;
albuns = (Album**) realloc (albuns,(sizeof(Album*) * aux));
albuns[*n_albuns] = (Album*) malloc (sizeof(Album));
(*n_albuns)++;
but the function returns me a SegFault in this line:
albuns[*n_albuns] = (Album*) malloc (sizeof(Album));
Any ideias? I'm relatively new to memory allocation
There are several issues with the question code. See impeded comments.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Question code should include a model of the structure. */
typedef struct Album_s
{
int a;
char b;
int *c;
char *d;
struct Album_s *e;
} Album;
/* Question indicates: void AddAlbum (int* n_albuns, Album** albuns);
** However, in order to change the size of the array, the address of the
** array must be supplied. Hence, the change from **albuns to ***albuns.
*/
int AddAlbum(int *n_albuns, Album ***albums)
{
int rCode = EXIT_SUCCESS;
void *newMem = NULL;
/* Attempt to increase the size of the array by one (pointer) element.
** The question code casts (Album**) the value returned by realloc(),
** which is not necessary. It is also important to verify that the call
** to realloc() actually succeeded. The realloc code below is fairly
** customary in order to check for this.
*/
newMem = realloc(*albums, sizeof(Album *) * (*n_albuns + 1));
if(!newMem)
{
rCode=errno;
goto CLEANUP;
}
*albums = newMem;
/* Again, the question code casts (Album*) the value returned by malloc(),
** which is not necessary. Being that the albums parameter is a pointer
** to a pointer to a pointer, the following assignment is correct. Again,
** it is important to verify that the call to malloc() actually succeeded.
*/
(*albums)[*n_albuns] = malloc(sizeof(Album));
if(!(*albums)[*n_albuns])
{
rCode=errno;
goto CLEANUP;
}
(*n_albuns)++;
CLEANUP:
return(rCode);
}
/* Example of how AddAlbum() might be called. */
int main(void)
{
int rCode = EXIT_SUCCESS;
Album **albunArray = NULL;
int albunCnt = 0;
int desiredCnt = 10;
while(albunCnt < desiredCnt)
{
rCode=AddAlbum(&albunCnt, &albunArray);
if(rCode)
{
fprintf(stderr, "AddAlbum() failed. errno: %d \"%s\"\n", rCode, strerror(rCode));
goto CLEANUP;
}
printf("Array element %d of %d added.\n", albunCnt, desiredCnt);
}
CLEANUP:
return(rCode);
}
Related
Say I want to dynamically allocate memory but with a function instead of in the main() function.
So I tried to do this:
dynamAlloc(int *fPtr)
{
fPtr=malloc(cols * sizeof(*fPtr) );
if(fPtr==NULL)
{
printf("Can't allocate memory");
exit(1);
}
}
Then I realised: Even though memory allocated on the heap is available for the lifetime of program, that memory can only be referenced by formal argument fPtr and not the actual argument(let's call it aPtr). But once, function is exited, that memory is lost.
So how then do I dynamically allocate memory with a function?
that memory can only be referenced by formal argument fPtr and not the actual argument(let's call it aPtr).
aPtr cannot denote to the heap memory object before the call to dynamAlloc() because the object has not been allocated yet and its address assigned to aPtr trough fPtr. Thereafter aPtr do reference the heap object.
We just need to pass the address of the pointer of aPtr to dynamAlloc(). So you need appropriate arguments(actual arguments) and parameters (formal arguments) to pass the address of the pointer aPtr between the functions, like you see below.
So how then do I dynamically allocate memory with a function?
You do it like you do it main(), doesn´t matter if the pointer was declared inside of main() or another function, you just need to pass the address of the pointer aPtr to the other functions, in which you want to use the heap memory object, like f.e.:
#include <stdio.h>
#include <stdlib.h>
#define cols 5
void dynamAlloc(int** fPtr);
int main()
{
int* aPtr;
dynamAlloc(&aPtr);
free(aPtr);
return 0;
}
void dynamAlloc(int** fPtr)
{
*fPtr = malloc(sizeof(*fPtr) * cols);
if(*fPtr == NULL)
{
printf("Can't allocate memory");
exit(1);
}
}
Do not forget to free() the heap memory!
or just make it like this:
void dynamAlloc(int **fPtr)
{
*fPtr=malloc(cols * sizeof(**fPtr) ); // malloc is returning void* so in that place it would be compiler error, so pointer returned from malloc should be casted to the pointer type of the value.
if(*fPtr==NULL) // that would be a warning in gcc since NULL is a macro eq to 0, or (void*)0, it compiler version
{
printf("Can't allocate memory");
exit(1);
}
}
and the fuction usage:
int* ptr = (int*)NULL;
dynamAlloc(&ptr);
*ptr = 1; // assign 1 to the first element, ptr is a valid pointer here
but double pointer syntax can turn out slow in some conditions, answer with return in the end od fucntion, copy of that local pointer is better practise.
As you need to change the pointer itself - pointer to pointer is needed
void *allocate(void **tmp, size_t size)
{
if(tmp)
{
*tmp = malloc(size);
}
return *tmp;
}
int main()
{
int *ptr;
if(!allocate((void**)&ptr, sizeof(*ptr) * 100))
{
perror("Error\n");
exit(1);
}
/* do something*/
free(ptr);
}
It's more convenient to use a macro function, like this:
#include <stdio.h>
#include <stdlib.h>
#define NEW_ARRAY(ptr, n) \
{ \
(ptr) = malloc((size_t) (n) * sizeof (ptr)[0]); \
if ((ptr) == NULL) { \
fputs("Can't allocate memory\n", stderr); \
exit(EXIT_FAILURE); \
} \
}
#define NEW(ptr) NEW_ARRAY((ptr), 1)
int main(void)
{
int *myArray;
const int myArrayLen = 100;
int i;
NEW_ARRAY(myArray, myArrayLen);
for (i = 0; i < myArrayLen; i++) {
/*...*/
}
return 0;
}
Update:
The purpose of the macro is to abstract away the details and make memory allocation less error prone. With a (non-macro) function we would have to pass the element size as a parameter as that information is lost when a pointer is passed to a formal parameter of type void pointer:
void NewArray(void *ptr, int n, int elemSize)
{
*ptr = malloc((size_t) n * sizeof elemSize);
if (*ptr == NULL) {
fputs("Can't allocate memory\n", stderr);
exit(EXIT_FAILURE);
}
}
With the function NewArray the allocation call corresponding to the first example becomes
NewArray(&myArray, n, sizeof myArray[0]);
which doesn't buy us much.
My question is aboutt dynamic memory allocation in C. I have been asked to dynamically allocate an array of n longs, and return the pointer to the first element of this array. I have some code to test the output of this but the memory allocation is failing.
long* make_long_array(long n)
{
int i;
int *a;
a = (int*)malloc(sizeof(int)*n);
if (a == NULL) {
printf("ERROR: Out of memory\n");
return 1;
}
for (i = 0; i < n; *(a + i++) = 0);
return *a;
}
Im getting an error on two lines saying
'error: return makes pointer from integer without cast'
this occurs for the lines
return 1;
and
return *a;
I'm not entirely sure how to fix this. I think the error in return 1; being that I am trying to return an integer when it is looking for a pointer? But I am not sure how to fix it for the return of the pointer. Any help would be much appreciated.
To fix your original version:
long* make_long_array(/* long not the correct type for sizes of objects */ size_t n)
{
// int i; define variables where they're used.
/* int you want to return a */ long *a; // array.
a = /* (int*) no need to cast */ malloc(sizeof(/* int */ you want */ long /*s, remember? *) */ ) * n);
if (a == NULL) {
printf("ERROR: Out of memory\n"); // puts()/fputs() would be sufficient.
return /* 1 */ NULL; // 1 is an integer. Also it is uncommon to return
} // anything other than NULL when a memory allocation
// fails.
for (size_t i = 0; i < n; /* *(a + i++) = 0 that falls into the category obfuscation */ ++i )
/* more readable: */ a[i] = 0;
// return *a; you don't want to return the first long in the memory allocated
return a; // but the address you got from malloc()
}
A Better Waytm to write such allocations is
FOO_TYPE *foo = malloc(NUM_ELEMENTS * sizeof(*foo)); // or
BAR_TYPE *bar = calloc(NUM_ELEMENTS, sizeof(*bar));
By using *foo and *bar as the operand of sizeof you don't have to worry about changing it when the type of foo or bar changes.
Your function can be simplified to
#include <stddef.h> // size_t
#include <stdlib.h> // calloc()
long* make_long_array(size_t size) // size_t is guaranteed to be big enough to hold
{ // all sizes of objects in memory and indexes
return calloc(size, sizeof(long)); // into them. calloc() initializes the memory
} // it allocates with zero.
// if you really want an error-message printed:
long* make_long_array(size_t size)
{
long *data = calloc(size, sizeof(long));
if (!data) // calloc() returned NULL
fputs("Out of memory :(\n\n", stderr); // Error messages should go to stderr
return data; // since it is unbuffered*) and
} // might be redirected by the user.
*) so the user gets the message instantly.
Also there is no need to cast the result of *alloc() since they return a void* which is implicitly convertible in every other pointer type.
Could be written as a macro so it not only works for long but for any type:
#include <stddef.h>
#include <stdlib.h>
#define MAKE_ARRAY(TYPE, COUNT) calloc((COUNT), sizeof((TYPE)))
// sample usage:
int main(void)
{
int *foo = MAKE_ARRAY(*foo, 12);
long *bar = MAKE_ARRAY(*bar, 24);
char *qux = MAKE_ARRAY(*qux, 8);
free(qux);
free(bar);
free(foo);
}
I'm starting with an array array[0] let's say.
As I loop through a text file and find keywords I'd like to store those words in that array.
So the first run though I'd assing the first keyword very simply
array[0] = "Word"
However I'm not sure how to increment that array to 1, and 2, etc.
I've read a few posts on memory allocaiton but that seemed to be specific to strings; perhaps I'm misunderstanding the concept.
I'd like to preserve the current array's contents, and increment it.
I've rigged it by setting my array[10], but I'd prefer to learn the correct way to do this.
I've included the code below so far (without any memory allocation)
#include <stdio.h>
#include <memory.h>
#include "tables.h"
int main() {
insertVarbleTble("Name","CSTRING",1,0,"");
return 0;
}
int insertVarbleTble(char *ident, char *type, int local, int constVar, char *constVal){
int successful;
int sizeArry;
sizeArry = sizeof(varible)/ sizeof(varible[0]);
if(sizeArry <= 0){
varible[sizeArry]== ident;
}else{
successful = (searchVarbleTble(ident,sizeArry)==1;
}
if(successful ==0){
varible[sizeArry+1]==ident;
}else{
printf("Already exists");
}
}
void realocMem(int size){
varible[size];
}
int searchVarbleTble(char * ident, int arrySize){
int i;
int results = 0;
for(i=0;i<arrySize;i++){
if(!strcmp(varible[i],ident)){
results= 1;
}
}
return results;
}
Header file contains the array I'm using they are:
char varible[0];
int insertVarbleTble(char *, char *, int, int , char *);
int searchVarbleTble(char *, int);
Would a potential solution be to first count the number of keywords that exist, and then dimension the array?
Okay generally what you want to do is not possible with arrays. Your code is really hard to understand but I will try to give you an example on how it is done.
This is not directly what you want, but should help you find your own solution. If you want to work with strings it gets a bit more complicated because strings are arrays in itself so you have to make sure that you always have enough memory for your current string available.
#include <stdio.h>
#include <stdlib.h>
typedef struct data_container_{
int *mem;
int size;
} data_container;
void add_to_memory(data_container *data, int pos, int value)
{
if (pos+1 > data->size) //check if memory for this position is allocated
{
int *dummy = realloc(data->mem, pos+1); // call realloc to get more memory
if(dummy == NULL) //check if reallocation was succesful
{
puts("Memory reallocation failed");
exit(1); //terminate program
}
else
{
data->size = pos+1; //set size to the newly allocated size
data->mem = dummy; //if succesful point to the new memory location
}
}
data->mem[pos] = value;
}
int main(void)
{
data_container data; // create stuct
data.size = 2;
data.mem = malloc(sizeof (int) * data.size); //allocate memory, similar to an array but dynamic
if(data.mem == NULL) //check if allocation was succesful
{
puts("Memory allocation failed");
exit(1); //terminate program
}
add_to_memory(&data, 0, 3); //pass the address of the struct
add_to_memory(&data, 1, 6);
add_to_memory(&data, 2, 8); //now it uses realloc, pos would be out of the allocated range
for(int i =0; i<data.size; i++)
{
printf("%d\n",data.mem[i]); //a pointer can be accessed similar to an array
}
free(data.mem); //free the allocated memory
}
as Pablo said you should read about malloc and realloc especially you should keep in mind that the memory allocated is not initialized. calloc initializes with 0.
And always remember to free allocated space when it is not used anymore.
I want to create a new intarr_t with initial size len, but I've never handled this type of problem with a typedef'ed variable.
My problem is that intarr_create() should allocate the array space and then return a pointer to it if malloc was successful or a pointer to NULL if I failed. How can I fix this?
Also, why there is a * symbol in the function?
Here's my code:
#include <stdio.h>
typedef struct {
int* data;
unsigned int len;
} intarr_t;
intarr_t* intarr_create(unsigned int len) {
//intarr_t with initial size len
intarr_t = (int *) malloc(len); // not working here, can someone explain why?
if(intarr_t != NULL) {
return intarr_t;
} else {
return NULL;
}
}
int main() {
int len = 15;
int h = intarr_create(len);
printf("%d\n", h);
return 0;
}
It's not working because you did not give your variable a name. Also, int* and intarr_t are not the same type, so you will get a type mismatch unless you change the cast.
Rewrite your function into this:
intarr_t* intarr_create(unsigned int len)
{
intarr_t *result;
result = (intarr_t *)malloc(sizeof(intarr_t)); // allocate memory for struct
if(result != NULL)
{
result->data = (int *)malloc(len * sizeof(int)); // allocate memory for data
result->len = len;
if (result->data == NULL)
{
/* handle error */
}
}
else
{
/* handle error */
}
return (result);
}
You have to do a "double" malloc to get it right. First you have to allocate the memory for the intarr_t and if that was successful you have to allocate the memory for the data array.
Additionally malloc returns a void * which must be cast to the correct pointer type (should be a warning or maybe even an error with some compilers).
You have a few problems with your intarr_create function. First of all, you need to name your intarr_t variable. Now you have the slightly trickier problem of allocating memory for the actual array of integers in addition to your intarr structure. Remember, that you will have to call delete twice to destroy this object. Once on the data, and once on the actual structure itself.
intarr_t* intarr_create(unsigned int len)
{
intarr_t* array = (intarr_t*)malloc(sizeof(intarr_t));
array->data = (int*)malloc(len * sizeof(int));
return array;
}
This is one of those annoying things where you know the answer is easy, but you just can't see it.
The printf statement in AllocIntArray shows that arrayPtr is correctly being assigned a memory location, however when the printf statement in main is run, it shows arrayB is still set to NULL.
Can someone show me what I am doing wrong when passing in arrayB to AllocIntArray?
#include <stdio.h>
#include <stdlib.h>
void AllocIntArray(int *arrayPtr, int numElements);
int main()
{
int *arrayB = NULL;
AllocIntArray(arrayB, 10);
printf("Pointer: %p\n", arrayB);
free(arrayB);
getchar();
return EXIT_SUCCESS;
}
void AllocIntArray(int *arrayPtr, int numElements)
{
arrayPtr = (int *)malloc(sizeof(int) * numElements);
printf("Pointer: %p\n", arrayPtr);
if(arrayPtr == NULL)
{
fprintf(stderr, "\nError allocating memory using malloc");
exit(EXIT_FAILURE);
}
}
Pass the double pointer.
#include <stdio.h>
#include <stdlib.h>
void AllocIntArray(int **arrayPtr, int numElements);
int main()
{
int *arrayB = NULL;
AllocIntArray(&arrayB, 10);
printf("Pointer: %p\n", arrayB);
free(arrayB);
getchar();
return EXIT_SUCCESS;
}
void AllocIntArray(int **arrayPtr, int numElements)
{
*arrayPtr = malloc(sizeof(int) * numElements);
printf("Pointer: %p\n", *arrayPtr);
if(*arrayPtr == NULL)
{
fprintf(stderr, "\nError allocating memory using malloc");
exit(EXIT_FAILURE);
}
}
That's because arrayB is passed to AllocIntArray by value. Either pass it by reference (with a pointer-to-pointer), or better, return it from AllocIntArray:
int *AllocIntArray(int numElements)
{
int *arrayPtr = malloc(sizeof(int) * numElements);
printf("Pointer: %p\n", arrayPtr);
if(arrayPtr == NULL)
{
fprintf(stderr, "\nError allocating memory using malloc");
exit(EXIT_FAILURE);
}
return arrayPtr;
}
You need to brush up a bit on parameter passing to functions.
The pointer you are sending to AllocIntArray is being copied into arrayPtr, The line
arrayPtr = (int *)malloc(sizeof(int) * numElements);
assigns a value into the copy, and not the original variable, and therefore the original variable still points to nowhere.
First solution that comes to mind is to send a pointer to that pointer, but I think you'd best do some general brushing up on the matter of parameter passing before going much further.
arrayPtr is a pointer and the pointer is passed by value to the parameter. AllocIntArray can modify its version of arrayPtr but the changes won't be seen by main().
(Edit: if you're using C++) modifying the signature for AllocIntArray to change the type of arrayPtr to a reference ought to fix your problem.
void AllocIntArray(int *&arrayPtr, int numElements)
The basic problem here is you are passing arrayB to AllocIntArray function as passed by value .In AllocIntArray its allocating memory properly and arrayptr is valid but in main function its not the same memory which you are expecting .
This is the basic C programming concept and you can check bu adding print in both the function .
EX: I am sharing the difference between both problem and success case with below example .
/*Code with passed by value as a parameter*/
#include<stdio.h>
#include<stdlib.h>
void AllocateIntarray(int *arrayptr,int numElements)
{
arrayptr = (int*) malloc(sizeof(int)*numElements);
printf("Inside _func_AllocateIntarray_pointer:%p\n",arrayptr);
if(arrayptr == NULL)
{
printf("ERR_MEM_ALLOCATION_FAILED:\n");
}
}
int main()
{
int *arrayB = NULL;
AllocateIntarray(arrayB,10);
printf("Inside _func_mainPointer:%p\n",arrayB);
free(arrayB);
return 0;
}
/*Output :
Inside _func_AllocateIntarray_pointer:0x55be51f96260
Inside _func_mainPointer:(nil)*/
Code with Passed by reference and using double pointer .
#include<stdio.h>
#include<stdlib.h>
void AllocateIntarray(int **arrayptr,int numElements)
{
*arrayptr = malloc(sizeof(int)*numElements);
printf("Inside _func_AllocateIntarray_pointer:%p\n",*arrayptr);
if(*arrayptr == NULL)
{
printf("ERR_MEM_ALLOCATION_FAILED:\n");
}
}
int main()
{
int *arrayB = NULL;
AllocateIntarray(&arrayB,10);
printf("Inside _func_mainPointer:%p\n",arrayB);
free(arrayB);
return 0;
}
/*Output :
Inside _func_AllocateIntarray_pointer:0x562bacd1f260
Inside _func_mainPointer:0x562bacd1f260*/