How do you use malloc of struct inside a function? - c

In a this code,
#include <stdio.h>
#include <stdlib.h>
typedef struct test
{
int i;
double data;
} test;
void add(ar) struct test *ar;
{
int num = 10;
// *ar = malloc(num * sizeof(struct test)); // Adding this
for (int i = 0; i < num; i++)
{
ar[i].i = i;
ar[i].data = i * i;
}
}
int main(void)
{
test ar[10]; // Removing this
add(&ar);
for (int i = 0; i < 10; i++)
{
printf("%d %f\n", ar[i].i, ar[i].data);
}
return 0;
}
How do we define the struct in main but allocate the memory in the function?
I want to set the number (num) inside the function add, as it is not yet known in main.

There are two values you have to pass back from add() to main(), num and the malloc()ed array itself. As you can return only one value, there are two positilities:
a) return num and have a test ** parameter to pass back the array
int add( struct test **ar )
{
int num = 10;
*ar = malloc( num * sizeof **ar );
// initialize everything, you have to replace ar[i] by (*ar)[i]
return num;
}
call it
struct test *ar;
int num = add( &ar );
b) return the array and have a int * parameter to pass back num
struct test *add( int *num )
{
*num = 10;
struct test *ar = malloc( *num * sizeof *ar );
// initialize everything as you do now
return ar;
}
call it
int num;
struct test *ar = add( &num );
As #Bodo mentioned, either way, you have to call free( ar ); in main() when you don't need ar anymore. You could call it directly or think about having a cleanup function like free_test( struct test *ar, int num ); that does the job. Such a function is especially useful if you have more malloc()s to allocate memory for the single struct elements (eg. if they contained char * elements to store strings).

use the argument(s) to pass argument(s)
use the return value to return stuff to the caller
#include <stdio.h>
#include <stdlib.h>
struct test
{
int i;
double data;
} ;
struct test *test_create(unsigned ntest)
{
struct test *pp;
unsigned idx;
pp = malloc(sizeof *pp * ntest);
for (idx = 0; idx < ntest; idx++)
{
pp[idx].i = idx;
pp[idx].data = idx * idx;
}
return pp;
}
int main(void)
{
struct test *ptr;
ptr = test_create(10);
for (int i = 0; i < 10; i++)
{
printf("%d %f\n", ptr[i].i, ptr[i].data);
}
return 0;
}
Update: if you want to return more than a single item, you could put the items together in a struct:
#include <stdio.h>
#include <stdlib.h>
struct dope {
unsigned size;
struct {
int i;
double data;
} *array;
} ;
struct dope *dope_create(void)
{
struct dope *pp;
unsigned omg =10;
pp = malloc(sizeof *pp );
pp->array = malloc(sizeof *pp->array * omg);
pp->size = omg;
for (omg = 0; omg < pp->size; omg++)
{
pp->array[omg].i = omg;
pp->array[omg].data = omg * omg;
}
return pp;
}
int main(void)
{
struct dope *ptr;
ptr = dope_create();
for (int iii = 0; iii < ptr->size; iii++)
{
printf("%d %f\n", ptr->array[iii].i, ptr->array[iii].data);
}
return 0;
}

You have already good answers as alternatives. Anyway I will show you code for 2 common ways of writing this.
As I see in your code, the factory function will determine the actual number of structs test to allocate. I will in the example:
generate a random number of structs, using rand() since it makes no difference here
fill them in like (1,1.01), (2,2.02) ... just to have a known value for testing
show the structs' contents on screen
free() them at exit
assume that can also be 0 structures created
1: use a NULL-terminated sequence of pointers
As it is used with success in all C strings :) we can use it here. As in strings (C strings), you need to search for the terminator in order to get the array size (Of course you can set the first pointer apart for the size, Pascal-like). It can or can not be of importance to know before-hand the # of structs.
Test** add_vector()
{
// returns a null terminated array of pointers
// to 'Test', pointing to actual instances of
// 'Test', allocated and numbered with 'i' starting
// at 1 and 'data' starting at 1.01
int num = rand() % 10; // 0 to 9 Test
fprintf(stderr,
"add_vector(): creating %d structs\n", num);
// at least one pointer, the terminating one
Test** ar = (Test**)malloc((1 + num) * sizeof(Test*));
int ix = 0;
for (ix = 0; ix < num; ix += 1)
{
ar[ix] = (Test*)malloc(sizeof(Test));
// sets up ar[i] to a known value
ar[ix]->i = 1 + ix;
ar[ix]->data = 1 + ix + (1 + ix) / 100.;
}; // for()
ar[ix] = NULL; // the terminator one, as in strings
return ar;
}
To use it you just call
Test** vector = add_vector();
as you see in the example below. A single pointer is returned. No need for arguments. If the number of structs is zero a single pointer is returned, like it would be with an empty string.
The # of structs is defined inside the function, and all structs instances are allocated and numbered before returning to caller.
2: return a pointer to a struct
typedef struct
{
int i;
double data;
} Test;
typedef struct
{
unsigned size;
Test* test;
} V_Test;
V_Test* add_struct();
The allocation function returns a pointer to a V_Test struct, that contains an array of Test strucs and a size elements, an in main() for every C program
int main(in argc, char** argv)
Here is the code:
V_Test* add_struct()
{
// returns a vector of structs inside V_Test,
// with known 'size', like in main( int,char**)
// The structs are initialized with 'i' starting
// at 1 and 'data' starting at 1.01
unsigned num = rand() % 10; // 0 to 9 Test
fprintf(stderr, "add_struct(): creating %d structs\n", num);
V_Test* v = (V_Test*) malloc(sizeof(V_Test));
v->size = num;
if (num == 0)
{
v->test = NULL;
return v;
};
v->test = (Test*)malloc(num * sizeof(Test));
for (unsigned ix = 0; ix < num; ix += 1)
{
v->test[ix].i = 1 + ix;
v->test[ix].data = 1 + ix + (1 + ix) / 100.;
}; // for()
return v;
}
To used it you just call
V_Test* vector = add_struct();
And here also there are no arguments. A new V_Test is allocated and returned.
Also here the # of structs is defined inside the function, and all structs instances are allocated and numbered before returning to caller.
In the code you will see a way of use both functions, create the structs, fill them in, display the contents and release the allocated memory.
Example output
add_vector(): creating 9 structs
# 1: [1, 1.01]
# 2: [2, 2.02]
# 3: [3, 3.03]
# 4: [4, 4.04]
# 5: [5, 5.05]
# 6: [6, 6.06]
# 7: [7, 7.07]
# 8: [8, 8.08]
# 9: [9, 9.09]
9 records were created
9 records were free()'d
add_struct(): creating 4 structs
# 1: [1, 1.01]
# 2: [2, 2.02]
# 3: [3, 3.03]
# 4: [4, 4.04]
4 records were created
4 records were free()'d
C Code
I compiled just once under MSVC.
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int i;
double data;
} Test;
typedef struct
{
unsigned size;
Test* test;
} V_Test;
V_Test* add_struct();
Test** add_vector();
void as_vector_of_pointers();
void as_struct_of_struct();
int main(void)
{
srand(210728);
as_vector_of_pointers();
as_struct_of_struct();
return 0;
}
Test** add_vector()
{
// returns a null terminated array of pointers
// to test
int num = rand() % 10; // 0 to 9 Test
fprintf(stderr,
"add_vector(): creating %d structs\n", num);
// at least one pointer, the terminating one
Test** ar = (Test**)malloc((1 + num) * sizeof(Test*));
int ix = 0;
for (ix = 0; ix < num; ix += 1)
{
ar[ix] = (Test*)malloc(sizeof(Test));
// sets up ar[i] to a known value
ar[ix]->i = 1 + ix;
ar[ix]->data = 1 + ix + (1 + ix) / 100.;
}; // for()
ar[ix] = NULL; // the terminator one, as in strings
return ar;
}
V_Test* add_struct()
{
// returns a vector of structs inside V_Test,
// with known 'size', like in
// main( int,char**)
unsigned num = rand() % 10; // 0 to 9 Test
fprintf(stderr, "add_struct(): creating %d structs\n", num);
V_Test* v = (V_Test*) malloc(sizeof(V_Test));
v->size = num;
if (num == 0)
{
v->test = NULL;
return v;
};
v->test = (Test*)malloc(num * sizeof(Test));
for (unsigned ix = 0; ix < num; ix += 1)
{
v->test[ix].i = 1 + ix;
v->test[ix].data = 1 + ix + (1 + ix) / 100.;
}; // for()
return v;
}
void as_struct_of_struct()
{
V_Test* vector = add_struct();
if (vector->size == 0)
{
printf("No records were created!\n");
free(vector);
return;
}
for ( unsigned count = 0; count < vector->size; count+=1)
{
printf("#%3d: [%d, %.2f]\n",
1 + count,
vector->test[count].i,
vector->test[count].data
);
}; // for()
printf("%d records were created\n", vector->size);
// to free() vector:
free(vector->test);
printf("%d records were free()'d\n", vector->size);
free(vector);
return;
};
void as_vector_of_pointers()
{
Test** vector = add_vector();
// now test the vector to count the number of
// records generated in the funcion
if (vector[0] == NULL)
{
printf("No records were created!\n");
free(vector);
return;
}
unsigned count = 0;
while (vector[count] != NULL)
{
printf("#%3d: [%d, %.2f]\n", 1 + count, (vector[count])->i,
(vector[count])->data);
count += 1;
};
printf("%d records were created\n", count);
// to free() vector, same way:
for (unsigned i = 0; i < count; i += 1) free(vector[i]);
free(vector);
printf("%d records were free()'d\n", count);
return;
}
SO vigilants: I always cast malloc() pointers, as I reminder to
myself and others reading the code. No implicit conversions. No need to pointing that.

Related

Invalid assignment on dynamic array C

Hello i am making a program in C which stores integers on a dynamic array which uses realloc every time it has to add a new element, i declare the array on the main:
int *abundants;
int count = abundant_numbers(&abundants);
once finished, i want to pass the modified array to another function to make other calculations
int abundant_numbers(int *abundants[]){
if (!(*abundants = (int*) malloc(sizeof(int)))){
perror("malloc error!\n");
exit(EXIT_FAILURE);
}
*abundants[0] = 12; //we know the very first abundant number
int count = 1, n = 14;
while (n < MAX_NUM){
if (is_abundant(n)) {
if (!(*abundants = (int*) realloc(*abundants,(count+1) * sizeof(int)))){
perror("Error in realloc\n");
exit(EXIT_FAILURE);
}
*abundants[count] = n;
count++;
}
n += 2; //no odd abundant numbers
}
return count;
}
the first time it enters on the if statement gives no problems, but the second time on the assignment i get a Segmentation Fault: 11, when accesing abundants[2], i dont understand why its not a valid position if it worked fine for abundants[1]
Thanks.
Your problem is a simple one in these lines:
*abundants[0] = 12;
*abundants[count] = n;
The indexing operator [] has higher precedence than the dereference operator *. So here you're treating your abundants as an array pointer directly and try to dereference the element. What you want instead is
(*abundants)[0] = 12;
(*abundants)[count] = n;
This should solve your problem, the remaining code will work correctly.
That being said, I would strongly suggest to use some data structure like this:
struct dynarr
{
size_t count;
size_t capacity;
int entries[];
}
and realloc() in larger chunks, always when your count reaches your capacity. realloc() is costly and you risk fragmenting your heap space in a typical heap-based implementation. Your code could look for example like this:
#include <stdio.h>
#include <stdlib.h>
#define MAX_NUM 1024
int is_abundant(int x) { return x; } // simple fake to make it compile, replace
struct dynarr
{
size_t count;
size_t capacity;
int entries[];
};
struct dynarr *createarr(size_t capacity)
{
struct dynarr *arr = malloc(sizeof(*arr) + capacity * sizeof(int));
if (!arr)
{
perror("malloc error!\n");
exit(EXIT_FAILURE);
}
arr->count = 0;
arr->capacity = capacity;
return arr;
}
struct dynarr *expandarr(struct dynarr *arr)
{
size_t capacity = arr->capacity * 2;
struct dynarr *newarr = realloc(arr,
sizeof(*newarr) + capacity * sizeof(int));
if (!newarr)
{
perror("malloc error!\n");
free(arr);
exit(EXIT_FAILURE);
}
newarr->capacity = capacity;
return newarr;
}
struct dynarr *abundant_numbers(void){
struct dynarr *abundants = createarr(32);
abundants->entries[abundants->count++] = 12; //we know the very first abundant number
int n = 14;
while (n < MAX_NUM){
if (is_abundant(n)) {
if (abundants->count == abundants->capacity)
{
abundants = expandarr(abundants);
}
abundants->entries[abundants->count++] = n;
}
n += 2; //no odd abundant numbers
}
return abundants;
}
int main(void)
{
struct dynarr *abundants = abundant_numbers();
for (size_t i = 0; i < abundants->count; ++i)
{
printf("%d ", abundants->entries[i]);
}
free(abundants);
putchar('\n');
}
the biggest problem is that the code is expecting an array of pointers to int.
But the code is only producing an array of `int`s
And the code contains several 'magic' numbers (2, 12, 14)
int *abundants = NULL;
int count = abundant_numbers(&abundants);
int abundant_numbers(int *abundants[])
{
if (!( abundants = malloc(sizeof(int))))
{
perror("malloc error!\n");
exit(EXIT_FAILURE);
}
abundants[0] = 12; //we know the very first abundant number
int count = 1;
int n = 14;
while (n < MAX_NUM)
{
if (is_abundant(n))
{
void *temp;
if (!( temp = realloc(abundants,(count+1) * sizeof(int))))
{
perror("Error in realloc\n");
free( abundants );
exit(EXIT_FAILURE);
}
// implied else, realloc successful
abundants = temp;
abundants[count] = n;
count++;
}
n += 2; //no odd abundant numbers
}
return count;
}
However, since MAX_NUM is a known value,
it would be better to just allocate that much memory in the beginning.
And strongly suggest to NOT have 'special' code
for special cases of the value of 'n'.
And give 'magic' numbers meaningful names, suggest via #define statements.
sample code follows:
#include <stdlib.h> // malloc(), free()
// use whatever value your program needs in the following statement.
#define MAX_NUM 1024
#define FIRST_ABUNDANT 12
#define STEP_AMOUNT 2
// prototypes
int abundant_numbers( int * );
int main( void )
{
int *abundants = NULL;
if (!( abundants = malloc(sizeof(int) * MAX_NUM)))
{
perror("malloc error!\n");
exit(EXIT_FAILURE);
}
// implied else, malloc successful
int count = abundant_numbers( abundants );
} // end function: main
int abundant_numbers( int *abundants )
{
int count = 0;
for( int n=FIRST_ABUNDANT; n < MAX_NUM; n+=STEP_AMOUNT )
{
if (is_abundant(n))
{
abundants[count] = n;
count++;
}
}
return count;
} // end function: abundant_numbers

An array that increases in size as a loop continues C

I'm trying to generate an array that increases in size as a while loop iterates. I know a pointer has something to do with the solution. Please look at the code below.
#include <stdio.h>
int main () {
int x = 0;
int *F = malloc(sizeof(int)); //I want F to start out as :-
F[0] = 1; // 1 by 1
F[1] = 2; // 1 by 2 such that it increases in size when assigned
int now = 2;
int evenSum = 2;
while (x <= 40000) {
F[now] = F[now-1] + F[now-2];
x = F[now];
if (F[now] % 2)
{
evenSum += F[now];
}
++now;
}
printf("The outcome is %d\n", evenSum);
//free(F);
// Yes this is problem 2 of euler challenge, i already got a working static model
}
Many Thanks in Advance
EDIT
What I'm actually looking for is the sum of all the even fib's up to a cut off limit of 40M. I could (what i did first time) sum the even numbers as i encounter them during the fib sequence. This meant i did not keep a array of some arbitary size. The purpose of this post is to create a growing memory that just keeps on consuming memory until it gets to the answer.
The following is the code I got from the brilliant answer that was given.
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
struct vector {
size_t size;
int *data;
};
void vector_resize(struct vector *vector, size_t size) {
if (vector->size >= size)
return;
while (vector->size < size)
vector->size *= 2;
vector->data = realloc(vector->data, sizeof(int) * vector->size);
assert(vector->data != NULL);
}
struct vector * vector_init() {
struct vector *vector = malloc(sizeof(*vector));
vector->size = 4;
vector->data = malloc(vector->size * sizeof(int));
return vector;
}
void vector_free(struct vector *vector) {
free(vector->data);
free(vector);
}
void vector_put(struct vector *vector, size_t index, int data) {
vector_resize(vector, index+1);
vector->data[index] = data;;
}
int vector_get(struct vector *vector, size_t index) {
vector_resize(vector, index+1);
return vector->data[index];
}
int main() {
struct vector *vector = vector_init();
int fibNow = 0;
int now = 2;
vector_put(vector, 0, 1);
vector_put(vector, 1, 2);
int evenSum = 2;
while (fibNow <= 4000000) {
fibNow = vector_get(vector, (now-1)) + vector_get(vector, (now-2));
vector_put(vector, now, fibNow);
if (fibNow % 2 == 0) {
evenSum += fibNow;
}
++now;
}
printf("The outcome is %d\n", evenSum);
// vector_put(vector, 0, 5);
// vector_put(vector, 9, 2);
// int i;
// for (i=0; i<10; ++i)
// printf("index 0: %d\n", vector_get(vector, i));
vector_free(vector);
}
So, In C we aren't allowed to overload the operator[]. But we could still create an object that functions like your request:
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
struct vector {
size_t size;
int *data;
};
void vector_resize(struct vector *vector, size_t size) {
if (vector->size >= size)
return;
while (vector->size < size)
vector->size *= 2;
vector->data = realloc(vector->data, sizeof(int) * vector->size);
assert(vector->data != NULL);
}
struct vector * vector_init() {
struct vector *vector = malloc(sizeof(*vector));
vector->size = 4;
vector->data = malloc(vector->size * sizeof(int));
return vector;
}
void vector_free(struct vector *vector) {
free(vector->data);
free(vector);
}
void vector_put(struct vector *vector, size_t index, int data) {
vector_resize(vector, index+1);
vector->data[index] = data;;
}
int vector_get(struct vector *vector, size_t index) {
vector_resize(vector, index+1);
return vector->data[index];
}
int main() {
struct vector *vector = vector_init();
vector_put(vector, 0, 5);
vector_put(vector, 9, 2);
for (int i=0; i<10; ++i)
printf("index 0: %d\n", vector_get(vector, i));
vector_free(vector);
}
Additionally, it's fun to look at a C++ version of what this could be. C++ makes this look far more like your original code, because we can overload operator[] for arbitrary objects.
#include <cstdio>
#include <vector>
template <typename T>
class auto_growing_vector {
private:
std::vector<T> data;
public:
T & operator[](size_t index) {
if (index >= data.size())
data.resize(index + 1);
return data[index];
}
};
int main() {
auto_growing_vector<int> vector;
vector[0] = 5;
vector[9] = 2;
for (int i=0; i<10; ++i)
printf("index 0: %d\n", vector[i]);
}
In general, realloc should do the trick for you. Example (this is just a snippet - you will need to do the rest yourself):
int *F;
F = malloc(2 * sizeof *F); // note you have to start with 2 elements for your code, not 1
F[0] = 1;
F[1] = 2;
// when you know you need to increase the size of F:
temp = realloc(F, n * sizeof *F); // where n is the new size in elements
if(temp != NULL) F = temp; // note that the block may have moved to a new place!
else {
printf("unable to grow the array to %d elements!\n", n);
free(F);
exit(0);
}
Of course for this problem you don't need to keep all the Fibonacci numbers - just the last two. This actually suggests a much simpler code. Let me start if for you, and see if you can finish it (since you are doing the Euler problems, which are all about figuring it out for yourself):
int first = 1;
int second = 1; // usually you start with 1,1,2,3,...
int temp, current;
int count;
int N = 4000; // where we stop
for(count = 2; count < N; count ++) {
current = first + second;
first = second;
second = current;
}
If you look closely, you can get even more efficient that this (hint, you really only need to keep one older value, not two...)
Reading the comments, if you want all the numbers in memory, you should just allocate enough space from the outset:
F = malloc(4000 * sizeof *F);
and no further manipulations are needed. Make sure your last index is 3999 in that case (since arrays are zero indexed).
I One way would be to use 2D array int[n][n], whith a lot of unused space
II Easier way would be to expend array size in every iteration by realocate function.
Just in that case, either:
a) every element of the original array would be a pointer to a new array of length i (i beeing iteration number), you would then realocate the original array to make size for new pointer, then allocate i*sizeof(int) of new memory for that new array that pointer would point to.
b) You would make linearized traingular matrix in which the original array will hold just numbers, not pointers. In every iteration you would expand it's size for i new elements. Linearized trangular matrix is a onedimensional array of numbers in which data is saved like this:
ordinary matrix: (/ = wasted memory)
A///
BC//
DEF/
GHIJ
linarized triangular matrix
ABCDEFGHIJ
You can acces linerized triangular matrix element E with coordinates [y,x] = [2,1] (element 'A' taken for origin) like
sum=0;
for(iy=0;iy<y;iy++)
for(ix=0;ix<=y && ix<x;ix++) sum++;
//myLinMatr[sum]=='E'

Manipulating a global array in a recursive function

I'm working through an algorithms MOOC and have a small program that takes an array A of ints in arbitrary order, counts the number of inversions (an inversion being the number of pairs (i,j) of array indices with i<j and A[i] > A[j]).
Below is the code I've written. I'm trying to tackle it using a "divide and conquer" approach where we recursively split the input array into two halves, sort each half individually while counting the inversions and then merge the two halves.
The trick is I need to keep track of the number of inversions and sort the arrays, so I pass the original array around the various recursive calls as an argument to the function and pass the count of inversions as a return value.
The code executes correctly through the first set of recursive calls that successively divide and sort [1,5,3], however when I get to the 3rd invocation of mergeAndCountSplitInv it crashes at the line:
sortedArrayLeft = realloc(sortedArrayLeft, sizeof(int)*(rightLen + leftLen));
with the error:
malloc: *** error for object 0x100103abc: pointer being realloc'd was not allocated
I can't see where I'm not using malloc correctly and I've combed through this checking to see I'm doing the pointer arithmetic correctly and can't spot any errors, but clearly error(s) exist.
Any help is appreciated.
// main.c
// inversionInC
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// function to help with debugging array/pointer arithmetic
void logArrayLenAndContents (char *arrayName, int arrayToPrint[], int arrayLen){
printf("%s\n", arrayName);
printf("len:%d\n", arrayLen);
for (int idx = 0; idx < arrayLen; idx++) {
printf("array[%d]: %d\n", idx, arrayToPrint[idx]);
}
}
int mergeAndCountSplitInv(int sortedArrayLeft[], int leftLen, int sortedArrayRight[], int rightLen)
{
printf("Calling mergeAndCount with sortedArrayLeft:\n");
logArrayLenAndContents("left Array", sortedArrayLeft, leftLen);
printf("...and sortedArrayRight:\n");
logArrayLenAndContents("right Array", sortedArrayRight, rightLen);
int i = 0;
int j = 0;
int k = 0;
int v = 0; // num of split inversions
int* outArray;
outArray = malloc((leftLen + rightLen) * sizeof(int));
while (i < leftLen && j < rightLen) {
if (sortedArrayLeft[i] < sortedArrayRight[j]) {
outArray[k] = sortedArrayLeft[i];
i++;
} else{
outArray[k] = sortedArrayRight[j];
v += leftLen - i;
j++;
}
k++;
}
// if at the end of either array then append the remaining elements
if (i < leftLen) {
while (i < leftLen) {
outArray[k] = sortedArrayLeft[i];
i++;
k++;
}
}
if (j < rightLen) {
while (j < rightLen) {
outArray[k] = sortedArrayRight[j];
j++;
k++;
}
}
printf("Wrapping up mergeAndCount where outArray contains:\n");
logArrayLenAndContents("outArray", outArray, k);
sortedArrayLeft = realloc(sortedArrayLeft, sizeof(int)*(rightLen + leftLen));
return v;
}
int sortAndCount(int inArray[], int inLen){
printf("Calling sortAndCount with:\n");
logArrayLenAndContents("inArray", inArray, inLen);
if (inLen < 2) {
return 0;
}
int inArrayLenPart1 = ceil(inLen/2.0);
int inArrayLenPart2 = inLen - inArrayLenPart1;
int* rightArray = malloc(sizeof(int) * inArrayLenPart2);
rightArray = &inArray[inArrayLenPart1];
int x = sortAndCount(inArray, inArrayLenPart1);
printf("sortAndCount returned x = %d\n\n", x);
int y = sortAndCount(rightArray, inArrayLenPart2);
printf("sortAndCount returned y = %d\n\n", y);
int z = mergeAndCountSplitInv(inArray, inArrayLenPart1, rightArray, inArrayLenPart2);
printf("mergeAndCount returned z = %d\n", z);
return x+y+z;
}
int main(int argc, const char * argv[])
{
static int* testArray;
testArray = malloc(5 * sizeof(int));
for (int i = 0; i<=4; i++) {
testArray[0] = 1;
testArray[1] = 5;
testArray[2] = 3;
testArray[3] = 2;
testArray[4] = 4;
}
int x = sortAndCount(testArray, 5);
printf("x = %d\n", x);
return 0;
}
This happens because the value of sortedArrayLeft gets lost as soon as the function returns. The realocated value does not make it to the caller, so inArray of the sortAndCount may be pointing to freed memory if realloc needs to reallocate and copy.
In order to fix this, pass a pointer to the pointer, letting sortedArrayLeft to propagate back to inArray of sortAndCount:
int mergeAndCountSplitInv(int **sortedArrayLeft, int leftLen, int sortedArrayRight[], int rightLen) {
...
*sortedArrayLeft = realloc(*sortedArrayLeft, sizeof(int)*(rightLen + leftLen));
return v;
}
...
int sortAndCount(int **inArray, int inLen) {
...
int z = mergeAndCountSplitInv(inArray, inArrayLenPart1, rightArray, inArrayLenPart2);
}
...
int x = sortAndCount(&testArray, 5);

Dynamic array in struct calloc or pointers failing, C

I'm attempting to complete an assignment on sparse matrices in C. I have a sparse matrix held as a list of values and coordinates and am converting it to Yale format.
I have run into a strange memory allocation issue that no one seems to have seen before. My code is:
yale* convertMatrix(matrix_list* input){
int matrix_elements = input->elements;
int matrix_rows = input->m;
yale* yale = (struct y*)calloc(1, sizeof(yale));
int* A = (int*)calloc(matrix_elements, sizeof(int));
int* IA = (int*)calloc(matrix_rows + 1, sizeof(int));
int* JA = (int*)calloc(matrix_elements, sizeof(int));
printf("%d elements\n",matrix_elements);
yale->A = A; // Value
yale->IA = IA; // Row (X)
yale->JA = JA; // Column (Y)
yale->elements = matrix_elements;
yale->m = matrix_rows;
yale->n = input->n;
list* tmp_list = input->first;
for(int i = 0, j = 0, tmp_y = 0; i < matrix_elements && tmp_list!=NULL; i++){
printf("Input Value: %d \n",tmp_list->point.value);
A[i] = tmp_list->point.value;
// Initialise the first row
if(i == 0) IA[0] = tmp_list->point.x;
else{
// Add a new row index
if(tmp_y != tmp_list->point.x){
j++;
IA[j] = i;
tmp_y = tmp_list->point.x;
}
}
JA[i] = tmp_list->point.y;
tmp_list = tmp_list->next;
}
for(int i = 0; i < matrix_elements; i++)
printf("%d,",yale->A[i]);
printf("\n");
for(int i = 0; i < matrix_rows + 1; i++)
printf("%d,",yale->IA[i]);
printf("\n");
for(int i = 0; i < matrix_elements; i++)
printf("%d,",yale->JA[i]);
return yale;
}
And here is the struct for yale:
typedef struct y{
int n;
int m;
int elements;
int *IA;
int *JA;
int *A;
} yale;
But the program segfaults at the first relevant printf on the first iteration of the loop.
printf("%d,",yale->A[i]);
I'm positive:
matrix_elements is an integer (9 in my test case)
matrix_rows is an integer
A / IA / JA are all filled with correct values (if you swap yale->A for A in the printf, it works fine).
Directly callocing the array to the struct pointers doesn't affect the result.
Mallocing, callocing, not typecasting, all no effect.
Thanks to Xcode and gdb I can also see that at the point of the segfault. The structure pointers do NOT seem to point to the arrays
I suggest you run your code under Valgrind. This should report the buffer overflow error. (A buffer overflow is where you write past the end of an array).
I also recommend you write some unit tests for your code. They can be very helpful detecting bugs. In particular, I suggest you write a test with a 3x3 input matrix with a value in every position. Check that the values you get out are what you expect.
To get it compiled, I need to prepend this to the snippet:
#include <stdlib.h>
#include <stdio.h>
typedef struct y{
int n;
int m;
int elements;
int *IA;
int *JA;
int *A;
} yale;
typedef struct list {
struct list *next;
struct point { int x,y,value; } point;
} list;
typedef struct matrix_list {
int elements;
int m;
int n;
struct list *first;
int *point;
} matrix_list;
UPDATE: I transformed the program into something more readable (IMHO). I don't have the faintest idea what the IA and JA are supposed to do, but the below fragment should be equivalent to the OP.
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
struct y {
unsigned int n;
unsigned int m;
unsigned int elements;
unsigned int *IA;
unsigned int *JA;
int *A;
} ;
struct list {
struct list *next;
struct point { unsigned int x,y; int value; } point;
} ;
struct matrix_list {
unsigned int elements;
unsigned int m;
unsigned int n;
struct list *first;
} ;
struct y *convertMatrix(struct matrix_list* input)
{
unsigned int matrix_elements = input->elements;
unsigned int matrix_rows = input->m;
unsigned int ii,jj,tmp_y;
struct y *yale ;
struct list *tmp_list ;
yale = calloc(1, sizeof *yale);
assert (yale != NULL);
printf("%u elements\n",matrix_elements);
yale->A = calloc(matrix_elements, sizeof *yale->A);
assert (yale->A != NULL);
yale->IA = calloc(matrix_rows + 1, sizeof *yale->IA);
assert (yale->IA != NULL);
yale->JA = calloc(matrix_elements, sizeof *yale->JA);
assert (yale->JA != NULL);
yale->elements = matrix_elements;
yale->m = matrix_rows;
yale->n = input->n;
// Initialise the first row, set start condition
// FIXME: this ignores the empty list or size=0 cases
yale->IA[0] = tmp_y = input->first->point.x;
ii = jj = 0;
for(tmp_list = input->first ;tmp_list; tmp_list = tmp_list->next) {
printf("Input Value: %d \n",tmp_list->point.value);
yale->A[ii] = tmp_list->point.value;
// Add a new row index
if(tmp_y != tmp_list->point.x){
jj++;
yale->IA[jj] = ii;
tmp_y = tmp_list->point.x;
}
yale->JA[ii] = tmp_list->point.y;
if (++ii >= matrix_elements ) break;
}
for(int i = 0; i < matrix_elements; i++)
printf("%d,",yale->A[i]);
printf("\n");
for(int i = 0; i < matrix_rows + 1; i++)
printf("%u,",yale->IA[i]);
printf("\n");
for(int i = 0; i < matrix_elements; i++)
printf("%u,",yale->JA[i]);
return yale;
}
Note: I moved the (ii == 0) {} condition out of the loop, and replaced the one-letter indices by there two-letter equivalents. Also: all the indices are unsigned (as they should be)

Unable to get array of structures initialized

I am passing a pointer to function and I want to initialze the array of structures in called function and want to use that array main function. But I was unable to get it in main function.
Here is my code:
typedef struct _testStruct
{
int a;
int b;
} testStruct;
void allocate(testStruct** t)
{
int nCount = 0;
int i = 0;
printf("allocate 1\n");
t = (testStruct**)malloc(10 * sizeof(testStruct));
for(i = 0; i < 10; i++)
{
t[i] = (testStruct *) malloc( 10 * sizeof(testStruct));
}
for(nCount = 0 ; nCount < 10; nCount++)
{
t[nCount]->a = nCount;
t[nCount]->b = nCount + 1;
printf( "A === %d\n", t[nCount]->a);
}
}
int main()
{
int nCount = 0;
testStruct * test = NULL;
int n = 0;
allocate(&test);
for(nCount = 0 ; nCount < 10; nCount++ )
{
if (test == NULL)
{
printf( "Not Allocated\n");
exit(0);
}
//printf("a = %d\n",test[nCount]->a);
/*printf("a = %d\n",test->a);
printf("b = %d\n",test->b); */
}
return 0;
}
Please note I have to pass double pointer to function as it is required.
Thank you for helping.
#include <stdio.h>
#include <stdlib.h>
typedef struct _testStruct
{
int a;
int b;
} testStruct;
void allocate(testStruct** t)
{
int nCount = 0;
printf("allocate 1\n");
testStruct *newT = (testStruct*)malloc(10 * sizeof(testStruct));
for(nCount = 0 ; nCount < 10; nCount++)
{
newT[nCount].a = nCount;
newT[nCount].b = nCount + 1;
printf( "A === %d\n", newT[nCount].a);
}
*t = newT;
}
int main()
{
int nCount = 0;
testStruct * test = NULL;
allocate(&test);
for(nCount = 0 ; nCount < 10; nCount++ )
{
printf("a = %d\n",test[nCount].a);
printf("a = %d\n",test[nCount].b);
}
return 0;
}
Should work.
t = (testStruct**)malloc(10 * sizeof(testStruct));
is assigning to t, not test. Perhaps you want
*t = (testStruct*)malloc(10 * sizeof(testStruct));
instead? I'm not sure, I tend to get lost when so many pointers are around. Anyway, you don't seem to be assigning anything into the pointer you pass to your function.
You say you want to create an array of structures, but your allocate function creates a data structure more like two-dimensional array. In addition, you don't return that structure back to the caller in any way that makes sense. I think you have come confusion about pointers, malloc() and all of the indirection you're doing. Check out #Ed Heal's answer for a corrected program.

Resources