Struct with variable size of array - c

I want to save data in arrays called plist. These arrays can vary in size and are part of a structure called ParticleList. I know how to create one list of size n[0]. n[0] for example is of size 2. Thus, a list of size 2. But what do I have to do, if I want to create several lists with size n[0], n[1], n[2] of type ParticleList?
To cut a long story short: How should I modify my code in order to access lists of variable size somehow like pl[numberOfList].plist[PositionInArray] = -1 or `pl[numberOfList] -> plist[PositionInArray] = -1'
#include <stdlib.h>
#include <stdio.h>
typedef struct{
double *plist;
int plistSize;
} ParticleList;
void sendPar(int *n, int nl){
// Allocate memory for struct ParticleList
ParticleList *pl = malloc(sizeof(ParticleList));
// Allocate memory for list
pl->plist = malloc(sizeof(double)*n[0]);
// Fill list with data
for(int k=0; k<n[0]; k++){
pl->plist[k] = -1;
}
// Write size of list into file
pl->plistSize = n[0];
// Print data
printf("Content of list:\n");
for(int k=0; k<n[0]; k++){
printf("%lf\n", pl->plist[k]);
}
printf("Size of list: %d\n", pl->plistSize);
// Free memory
free(pl);
}
int main(){
// Number of lists
int nl = 3;
// Size of lists
int n[nl];
n[0] = 2;
n[1] = 3;
n[2] = 4;
sendPar(n, nl);
}

Do you mean something like this?
typedef struct{
int plistSize;
double* plist;
} ParticleList;
int main()
{
int i, z = 0;
/* Assuming you have three lists with three different sizes */
double list1[2] = {-1.0, -1.1};
double list2[3] = {-2.0, -2.1, -2.2};
double list3[4] = {-3.0, -3.1, -3.2, -3.3};
/* Create an array of three Particle Lists */
ParticleList pl[3] = {{list1, 2},{list2, 3},{list3, 4}};
/* Access the values in the Particle Lists */
for(i = 0; i < 3; i++)
{
printf("ParticleList pl[%i]:\n", i);
for(z = 0; z < pl[i].plistSize; z++)
{
printf("pl[%i].plist[%i] = %f\n", i, z, pl[i].plist[z]);
}
}
/* Change the first item of the second list */
pl[1].plist[0] = 2.3;
}
This way you can access each item in each list by
pl[<index of list>].plist[<index of list item>]
A bit more dynamic by using flexible array members (this way one of the lists can be replaced by another list of different size):
Note that I changed the struct!
typedef struct{
int plistSize;
double plist[];
} ParticleList;
int main()
{
int i, z = 0;
ParticleList *pl[3];
/* Allocate memory for the lists */
pl[0] = malloc( sizeof(ParticleList) + sizeof(double[2]) );
pl[0]->plistSize = 2;
pl[1] = malloc( sizeof(ParticleList) + sizeof(double[3]) );
pl[1]->plistSize = 3;
pl[2] = malloc( sizeof(ParticleList) + sizeof(double[4]) );
pl[2]->plistSize = 4;
/* Write the values in the Particle Lists */
for(i = 0; i < 3; i++)
{
printf("ParticleList pl[%i]:\n", i);
for(z = 0; z < pl[i]->plistSize; z++)
{
pl[i]->plist[z] = -i;
}
}
/* Print the values */
for(i = 0; i < 3; i++)
{
printf("ParticleList pl[%i]:\n", i);
for(z = 0; z < pl[i]->plistSize; z++)
{
printf("pl[%i]->plist[%i] = %f\n", i, z, pl[i]->plist[z]);
}
}
/* Change the first value of the second list */
pl[1]->plist[0] = -1.1;
/* Replace the first list by a new one */
free(pl[0]);
pl[0] = malloc( sizeof(ParticleList) + sizeof(double[5]) );
pl[0]->plistSize = 5;
/* Assign some new values to the new list 1 */
pl[0]->plist[0] = -4.1;
pl[0]->plist[1] = -4.2;
pl[0]->plist[2] = -4.3;
pl[0]->plist[3] = -4.4;
pl[0]->plist[4] = -4.5;
/* Print the values */
for(i = 0; i < 3; i++)
{
printf("ParticleList pl[%i]:\n", i);
for(z = 0; z < pl[i]->plistSize; z++)
{
printf("pl[%i]->plist[%i] = %f\n", i, z, pl[i]->plist[z]);
}
}
/* free all lists before exiting the program */
for(i = 0; i < 3; i++)
{
free(pl[i]);
}
return 0;
}

It would seem you are looking for the language feature called flexible array member. It works like this:
typedef struct{
int plistSize;
double plist[];
} ParticleList;
ParticleList *pl = malloc( sizeof(ParticleList) + sizeof(double[n]) );
pl->plistSize = n;
...
free(pl);
Where n is the size you want plist to have.

Related

Why am I getting a segfault in this genetic algorithm problem?

I'm trying to solve a CodeWars problem called "Training on Binary Genetic Algorithms." There is a fitness function that is preloaded. When the program is run, a test function creates a random 35-bit string and it uses my run function which is supposed to return the same 35-bit string. This string is supposed to be found using a genetic algorithm.
Here is my code:
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
typedef double fitness_t (const char *, ...);
extern fitness_t fitness;
void generate (size_t length, char * s)
{
for (size_t i = 0; i < length; i++)
s[i] = rand() % 2 + 48;
}
double sum(size_t n, double ar[n])
{
double sum = 0;
for (int i = 0; i < n; i++)
sum += ar[i];
return sum;
}
void select (int size, char* population[size], double fitnesses[size])
{
double probabilities[size]; // normalized to 1
double r; // random number
int s1, s2;
int i;
for (i = 0; i < size; i++)
probabilities[i] = fitnesses[i] / sum(size, fitnesses);
// select first chromosome
r = (double)(rand() % 1000000) / 1000000; // generates a random float between 0 and 1
for (i = 0; i < size && r > 0; i++)
r -= probabilities[i];
s1 = i;
// select second chromosome
s2 = s1;
while (s2 == s1) // ensures the two chromosomes aren't the same
{
r = (double)(rand() % 1000000) / 1000000; // generates a random float between 0 and 1
for (i = 0; i < size && r > 0; i++)
r -= probabilities[i];
s2 = i;
}
// places these two chromosomes on top
char * temp = population[0];
population[0] = population[s1];
population[s1] = temp;
temp = population[1];
population[1] = population[s2];
population[s2] = temp;
}
void crossover (size_t n, char* s1, char* s2)
{
int r = rand() % n; // select a random bit to cross over at
char temp;
for (size_t i = r; i < n; i++) // swap every bit from bit r to bit n
{
temp = s1[i];
s1[i] = s2[i];
s2[i] = temp;
}
}
void mutate (size_t n, char* s, double p)
{
double r;
for (size_t i = 0; i < n; i++) // for each bit
{
r = (double)(rand() % 1000000) / 1000000; // random float between 0 and 1
if (r <= p) // if random number is less than probability
{
if (s[i] == '1') s[i] = '0'; // swap 0s and 1s
else s[i] = '1';
}
}
}
void bubbleSortPop(int size, char * population[size], double fitnesses[size])
{
int i, j;
char * temp_chrome;
double temp_fitness;
for (i = 0; i < size - 1; i++)
// Last i elements are already in place
for (j = 0; j < size - i - 1; j++)
if (fitnesses[j] < fitnesses[j + 1])
{
temp_chrome = population[j];
population[j] = population[j+1];
population[j+1] = temp_chrome;
temp_fitness = fitnesses[j];
fitnesses[j] = fitnesses[j+1];
fitnesses[j+1] = temp_fitness;
}
}
// this function changes the population.
// select, crossover, mutate
void evolve(fitness_t f, size_t size, int length, char * population[size],
double fitnesses[size], double p_c, double p_m)
{
char * s1, * s2;
double f1, f2;
char * temp_pop[size+2];
double temp_fit[size+2];
int i;
double r;
// moves two selected parents to the top
select(size, population, fitnesses);
// begin reproduction process; duplicate the chromosomes
s1 = population[0];
s2 = population[1];
// crossover
r = (double)(rand() % 1000000) / 1000000; // random float between 0 and 1
if (r < p_c) // probability of crossing over
crossover(length, s1, s2); // commences with crossover
// mutate
mutate(length, s1, p_m);
mutate(length, s2, p_m);
// calculate fitnesses
f1 = f(s1);
f2 = f(s2);
// merge fitneses
// copy original fitnesses into temp_fit
for (i = 0; i < size; i++)
temp_fit[i] = fitnesses[i];
// add new fitnesses
temp_fit[size] = f1;
temp_fit[size+1] = f2;
// merge children into population
// copy original population into temp_pop
for (i = 0; i < size; i++)
temp_pop[i] = population[i];
// add two children to temp_pop
temp_pop[size] = s1;
temp_pop[size+1] = s2;
// sort fitnesses and population
bubbleSortPop(size+2, temp_pop, temp_fit);
// add first 100 elements of temp_pop and fit to population and fitnesses
for (i = 0; i < size; i++)
{
population[i] = temp_pop[i];
fitnesses[i] = temp_fit[i];
}
}
char* runN (fitness_t f, int length, double p_c, double p_m, size_t iterations) {
}
char* run (fitness_t f, int length, double p_c, double p_m)
{
size_t size = 100;
char * population[size];
double fitnesses[size];
size_t i;
int r;
srand(time(0));
// initialize population array
for (i = 0; i < size; i++)
population[i] = malloc((length+1) * sizeof(char));
// generate original population
for (i = 0; i < size; i++)
{
generate(length, population[i]);
fitnesses[i] = f(population[i]);
printf("[%2d] %s %lf\n", i, population[i], fitnesses[i]);
}
// evolve the population
for (i = 0; i < 10; i++)
evolve(f, size, length, population, fitnesses, p_c, p_m);
// print result
printf("\nAFTER EVOLUTION\n");
for (i = 0; i < size; i++) // generates original population
printf("[%2d] %s %lf\n", i, population[i], fitnesses[i]);
// store best chromosome and free memory
char ret[length+1];
strcpy(ret, population[0]);
for (i = 0; i < size; i++)
free(population[i]);
return ret;
}
The issue is when I run my code, it nearly always comes out with a segfault at some point while printing the contents of population and fitness.
At least these problems:
Attempting to print a non-string with "%s"
Code uses "%s" and passes population[i] as if it points to a string. population[i] does not point to a string as it does not certainly have a null character. Result undefined behavior (UB). Perhaps attempting to access beyond allocated memory.
// Undefined behavior: population[i] not a string
printf("[%2d] %s %lf\n", i, population[i], fitnesses[i]);
Set the null character.
generate(length, population[i]);
population[i][length] = '\0'; // Add this here or equivalent in `generate()`.
Many compiler warnings (20+)
Enable all compiler warnings and fix those.
I found the solution. It was all the places where I tried to copy a string by making a string pointer and assigning it the same address as the pointer I wanted to copy. For example, in 'select', when I tried to move the two strings to the top, I did
char * temp = population[0];
population[0] = population[s1];
population[s1] = temp;
temp = population[1];
population[1] = population[s2];
population[s2] = temp;
I changed this to using strcpy(). I made the same mistake in 'evolve' where I tried to duplicate the chromosomes by just copying their address into variables, rather than the strings themselves:
char * s1, * s2;
// begin reproduction process; duplicate the chromosomes
s1 = population[0];
s2 = population[1];
I changed it to this:
char s1[length+1], s2[length+1];
strcpy(s1, population[0]);
strcpy(s2, population[1]);
After I made this change the segfault went away. Thanks for all your answers.

What is wrong with my C selection sort code below? what should I do in my void selection sort

so this is the command, create an array of structs (a total of 15 elements) consisting of variables of type int and string. sort the array and perform a search on the array based on one of the elements with a variable of type int. use straight selection sort and interpolation search. i'm very new on learning Selection Sort, please correct the code below, I've reached my limit.
#include <stdio.h>
#include <string.h>
#include <conio.h>
void swap(int *xp, int *yp) {
int temp = *xp;
*xp = *yp;
*yp = temp;
}
void selectionSort(int angka[], int n) {
int i, j, k;
for (i = 0; i < n-1; i++) {
k = i;
for (j = i+1 ; j < n; j++) {
if (angka[j] < angka[k]);
k = j;
}
swap(&angka[k], &angka[i]);
}
}
void printArray(int angka[], int size) {
int i;
for (i=0; i < size; i++) {
printf("%d", angka[i]);
}
printf("\n");
}
struct dat {
int angka;
const char* name;
};
int main () {
struct dat nama_var[15];
nama_var[0].angka = 4;
nama_var[0].name = "Farina";
nama_var[1].angka = 12;
nama_var[1].name = "Rima";
nama_var[2].angka = 7;
nama_var[2].name = "Jihan";
nama_var[3].angka = 1;
nama_var[3].name = "Audi";
nama_var[4].angka = 14;
nama_var[4].name = "Tantri";
nama_var[5].angka = 5;
nama_var[5].name = "Farhan";
nama_var[6].angka = 15;
nama_var[6].name = "Tedi";
nama_var[7].angka = 6;
nama_var[7].name = "Husain";
nama_var[8].angka = 9;
nama_var[8].name = "Laudia";
nama_var[9].angka = 13;
nama_var[9].name = "Sari";
nama_var[10].angka = 2;
nama_var[10].name = "Ardi";
nama_var[11].angka = 10;
nama_var[11].name = "10";
nama_var[12].angka = 8;
nama_var[12].name = "Johan";
nama_var[13].angka = 11;
nama_var[13].name = "Misbah";
nama_var[14].angka = 3;
nama_var[14].name = "CIndy";
I'm stuck about the code here
int n = sizeof(nama_var.angka)/sizeof(nama_var.angka[]);
selectionSort(nama_var[15], n);
printf("Sorted : \n");
printArray(angka, n);
getch();
}
In your nama_var array you have names and integers and you want to sort the array based on the integers, however you made a function that sorts an array of integers. Let's change your function a bit so it sorts structs instead :
void selectionSort(struct dat names[], int n);
void swap(struct dat *xp, struct dat *yp); /* struct dat *temp = *xp; */
You want to sort the structures according to their angka value, so you have to extract them from the structures in order to compare them :
if (angka[j] < angka[k])
becomes :
if (names[j].angka < names[i].angka)
Finaly I think you made two typos, the if statement was bypassed each time : a single semicolon is a valid statement in C.
for (j = i+1 ; j < n; j++) {
if (angka[j] < angka[k]) /* ; <---- */
k = j;
}
And you call the function which is supposed to take an array but by putting square brackets you are giving the element at index 15 (which is outside the array) :
selectionSort(nama_var[15], n);
What you were trying to do was :
selectionSort(nama_var, n);

Sorting a structure

I wanted to sort this problem in C with something like bubble sort ... anyone can help
Implement a list with 5 struct Point (Being this a point w/ X, y);
Sort the 5 struct point (first evaluate x then y).
Example:
// The points
p[0]={2,3}
p[1]={4,5}
p[2]={1,5}
p[3]={4,3}
p[4]={1,2}
// Should become
p[0]={1,2}
p[1]={1,5}
p[2]={2,3}
p[3]={4,3}
p[4]={4,5}
If you want to sort structures, you still have to break it down into comparing numeric types. With this in mind, let's take your example with the points:
struct tagPoint
{
int x;
int y;
};
typedef struct tagPoint Point;
Now, let's suppose you have an array of Point and you want it sorted. You can take two approaches:
1. Straightforward function which sorts the array:
Just make the function to sort the array:
void SortPointArray(Point* Points, unsigned int n)
{
/* This will sort the points with priority on the x and then the y value in ascending order. */
for(unsigned int i = 0; i < n-1; i++)
for(unsigned int j = i+1; j < n; j++)
{
if (Points[i].x > Points[j].x)
{
Point aux = Points[i];
Points[i] = Points[j];
Points[j] = aux;
}
else if ((Points[i].x == Points[j].x) && (Points[i].y > Points[j].y))
{
Point aux = Points[i];
Points[i] = Points[j];
Points[j] = aux;
}
}
}
2. Wrap the algorithm in a generic function and use callbacks for each type you want to sort:
This is a little more complicated, but it will save you some time if you use it frequently. Here, this function uses the same algorithm as the one above, but can sort any types.
void Sort(void* lpArray, unsigned int n, size_t cbSize, int (*Cmp)(void*, void*), void (*Swap)(void*, void*))
{
for(unsigned int i = 0; i < n-1; i++)
for(unsigned int j = i+1; j < n; j++)
/* Cast void* to char* to get rid of warning with pointer arithmetic... */
if ( Cmp( ((char*)lpArray) + i*cbSize, ((char*)lpArray) + j*cbSize) )
Swap( ((char*)lpArray) + i*cbSize, ((char*)lpArray) + j*cbSize );
}
As you can see, it requires 2 more functions passed as parameters. If you want this Sort function to know how to sort the Point array, you must define a Comparrison function and a Swapping function and tell the Sort function to use them.
Here is how i implemented them:
/** This function return 1 if p1 should be swapped with p2. */
int ComparePoints(void* vp1, void* vp2)
{
Point *p1, *p2;
p1 = vp1;
p2 = vp2;
if (p1->x > p2->x)
return 1;
else if ((p1->x == p2->x) && (p1->y > p2->y))
return 1;
return 0;
}
/** This will swap 2 points. */
void SwapPoints(void* vp1, void* vp2)
{
Point p = *(Point*)vp1;
*(Point*)vp1 = *(Point*)vp2;
*(Point*)vp2 = p;
}
How do you use them?
If you only want to use the first SortPointArray function, this is enough:
int main()
{
Point Array[10];
/* Read the points. */
for(unsigned int i = 0; i < 10; i++)
scanf("%d %d", &Array[i].x, &Array[i].y);
SortPointArray(Array, 10);
/*Print the points.*/
for(unsigned int i = 0; i < 10; i++)
printf("%d %d\n", Array[i].x, Array[i].y);
return 0;
}
But if you want to use the generic Sort function (which i recommend only if you have multiple types you want to sort like Points, Lines etc) you have to define the two callbacks (ComparePoints and SwapPoints)
int main()
{
Point Array[10];
/* Read the points. */
for(unsigned int i = 0; i < 10; i++)
scanf("%d %d", &Array[i].x, &Array[i].y);
Sort(Array, 10, sizeof(Point), ComparePoints, SwapPoints);
/*Print the points.*/
for(unsigned int i = 0; i < 10; i++)
printf("%d %d\n", Array[i].x, Array[i].y);
return 0;
}
The OP is asking for a C solution, so here you go:
void bsortDesc(struct yourStruct list[80], int s)
{
int i, j;
struct yourStruct temp;
for (i = 0; i < s - 1; i++)
{
for (j = 0; j < (s - 1-i); j++)
{
if (list[j].marks < list[j + 1].marks)
{
temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
}
}
}
}
Also, here's what I got it from: here.

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)

Resources