MPI dynamically allocation arrays - c

I have a problem with a dynamically allocation of arrays.
This code, if I use a static allocation, runs without problem...
int main (int argc, char *argv[]){
int size, rank;
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
int lowerBound = 0, upperBound = 0, dimArrayTemp, x, z;
int dimBulk = size - 1, nPart, cnt;
FILE *pf;
pf = fopen("in.txt","r");
int array_value = fscanf(pf,"%d",&array_value);
float ins_array_value;
float *arrayTemp, *bulkSum,*s,*a;
arrayTemp =(float*)malloc(array_value*sizeof(float));
bulkSum = (float*)malloc(array_value*sizeof(float));
s =(float*) malloc(array_value*sizeof(float));
a =(float*) malloc(array_value*sizeof(float));
int j=0;
while(!feof(pf)){
fscanf(pf,"%f",&ins_array_value);
a[j] = ins_array_value;
j++;
}
fclose(pf);
float presum, valFinal;
if(size <= array_value){
if (rank == MASTER){
nPart = array_value/size;
int countPair;
if((array_value % size) != 0){
countPair = 0;
}
for (int i = 0; i < size; i++){
if(i == 0){
lowerBound = upperBound;
upperBound += nPart - 1;
}
else{
lowerBound += nPart;
upperBound += nPart;
if(countPair == 0 && i == size - 1)
upperBound = array_value - 1;
}
dimArrayTemp = upperBound - lowerBound;
//float arrayTemp[dimArrayTemp];
for( x = lowerBound, z = 0; x <= upperBound; x++, z++){
arrayTemp[z] = a[x];
}
if (i > 0){
//send array size
MPI_Send(&z,1,MPI_INT,i,0,MPI_COMM_WORLD);
//send value array
MPI_Send(arrayTemp,z,MPI_INT,i,1,MPI_COMM_WORLD);
}
else{
for (int h = 1;h <= dimArrayTemp; h++)
arrayTemp[h] = arrayTemp[h-1] + arrayTemp[h];
bulkSum[0] = arrayTemp[dimArrayTemp];
for (int h = 0; h <= dimArrayTemp; h++)
s[h] = arrayTemp[h];
}
}
}
else{
//recieve array size
MPI_Recv(&z,1,MPI_INT,0,0,MPI_COMM_WORLD, &status);
MPI_Recv(arrayTemp,z,MPI_INT,0,1,MPI_COMM_WORLD,&status);
for(int h = 1; h < z; h++){
arrayTemp[h] = arrayTemp[h-1] + arrayTemp[h];
presum = arrayTemp[h];
}
MPI_Send(&presum,1,MPI_INT,0,1,MPI_COMM_WORLD);
}
//MPI_Barrier(MPI_COMM_WORLD);
if (rank == MASTER){
for (int i = 1; i<size;i++){
MPI_Recv(&presum,1,MPI_INT,i,1,MPI_COMM_WORLD,&status);
bulkSum[i] = presum;
}
for (int i = 0; i<=dimBulk; i++){
bulkSum[i] = bulkSum[i-1] +bulkSum[i];
}
for(int i = 0; i<dimBulk;i++){
valFinal = bulkSum[i];
cnt = i+1;
MPI_Send(&valFinal,1,MPI_INT,cnt,1,MPI_COMM_WORLD);
}
}
else{
MPI_Recv(&valFinal,1,MPI_INT,0,1,MPI_COMM_WORLD,&status);
for(int i = 0; i<z;i++){
arrayTemp[i] = arrayTemp[i] + valFinal;
}
MPI_Send(arrayTemp,z,MPI_INT,0,1,MPI_COMM_WORLD);
}
if(rank == MASTER){
for(int i =1;i<size;i++){
MPI_Recv(arrayTemp,z,MPI_INT,i,1,MPI_COMM_WORLD,&status);
for(int v=0, w =dimArrayTemp+1 ;v<z;v++, w++){
s[w] = arrayTemp[v];
}
dimArrayTemp += z;
}
int count = 0;
for(int c = 0;c<array_value;c++){
printf("s[%d] = %f \n",count++,s[c]);
}
}
}
else{
printf("ERROR!!!\t number of procs (%d) is higher than array size(%d)!\n", size, array_value);
//fflush(stdout);
MPI_Finalize();
}
free(arrayTemp);
free(s);
free(a);
free(bulkSum);
MPI_Finalize();
return 0;
}
This is a specific declaration of arrays:
float *arrayTemp, *bulkSum,*s,*a;
arrayTemp =(float*)malloc(array_value*sizeof(float));
bulkSum = (float*)malloc(array_value*sizeof(float));
s =(float*) malloc(array_value*sizeof(float));
a =(float*) malloc(array_value*sizeof(float));
Any ideas?
EDIT:
I'm deleted reference for arrays in MPI_Send(); and MPI_Recv(); and condition master, the same error is occurred: a process exited on signal 6 (Aborted).

This is a very common rookie mistake. One often sees MPI tutorials where variables are passed by address to MPI calls, e.g. MPI_Send(&a, ...);. The address-of operator (&) is used to get the address of the variable and that address is passed to MPI as a buffer area for the operation. While & returns the address of the actual data storage for scalar variables and arrays, when applied to pointers it returns the address where the address pointed to is stored.
The simplest solution is to stick to the following rule: never use & with arrays or dynamically allocated memory, e.g.:
int a;
MPI_Send(&a, ...);
but
int a[10];
MPI_Send(a, ...);
and
int *a = malloc(10 * sizeof(int));
MPI_Send(a, ...);
Also, as noted by #talonmies, you are only allocating the arrays in the master process. You should remove the conditional surrounding the allocation calls.

making arrays static prevents the arrays to be modified in other functions thus preventing errors. If making arrays static causes no errors then let it be static and use them by call by reference or it might be a good idea to make the arrays global as a try.

Related

Multiple C threads not returning correct values

I am trying to multiply two matrices using a different thread for each member of the resultant matrix. I have this code:
struct data{
int p;
int linie[20];
int coloana[20];
};
void *func(void *args){
struct data *st = (struct data *) args;
int c = 0;
for(int k = 0; k < st->p; k++){
c += st->linie[k] * st->coloana[k];
}
char *rez = (char*) malloc(5);
sprintf(rez, "%d", c);
return rez;
}
int main(int argc, char *argv[]){
int n = 2;
int m = 2;
int A[2][2] = {{1, 2},
{4, 5}};
int B[2][2] = {{7, 3},
{7, 5}};
int C[n][m];
char *res[n * m];
char *rez[n * m];
pthread_t threads[n * m];
int count = 0;
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
struct data st;
st.p = 2;
for(int x = 0; x < st.p; x++){
st.linie[x] = A[i][x];
st.coloana[x] = B[x][j];
}
pthread_create(&threads[count], NULL, func, &st);
count++;
}
}
for(int i = 0; i < n * m; i++){
pthread_join(threads[i], (void**) &rez[i]);
printf("%d ", atoi(rez[i]));
}
return 0;
}
But the correct result is never put into rez[i]. For example I get output "63 37 37 37".
The code works perfectly if I don't choose to wait for every thread to finish, i.e. I put that pthread_join right after pthread_create in the nested for loop. What should I do?
Thanks for reading!
Your first threading problem is here:
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
struct data st;
st.p = 2;
for(int x = 0; x < st.p; x++){
st.linie[x] = A[i][x];
st.coloana[x] = B[x][j];
}
pthread_create(&threads[count], NULL, func, &st);
count++;
}
}
All the threads get passed a pointer to the same variable, &st, which goes out of scope after each call to pthread_create(). You need to ensure that each thread gets its own variable, and that the variable lasts until the thread exits.
To fix this, for example, you could try:
struct data st[n * m];
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
st[count].p = 2;
for (int x = 0; x < st[count].p; x++)
{
st[count].linie[x] = A[i][x];
st[count].coloana[x] = B[x][j];
}
int rc = pthread_create(&threads[count], NULL, func, &st[count]);
if (rc != 0)
…report pthread creation error…
count++;
}
}
This gives each thread its own struct data to work on, and the structure outlasts the pthread_join() loop.
I'm not completely that it is a good scheme to make one copy of the relevant parts of the two arrays for each thread. It's not too painful at size 2x2, but at 20x20, it begins to be painful. The threads should be told which row and column to process, and should be given pointers to the source matrices, and so on. As long as no thread modifies the source matrices, there isn't a problem reading the data.
Updated answer which replaces the previous invalid code related to pthread_join() (as noted by oftigus in a comment) with this working code. There's a reason I normally test before I post!
On the whole, casts like (void **) should be avoided in the pthread_join() loop. One correct working way to handle this is:
for (int i = 0; i < n * m; i++)
{
void *vp;
int rc = pthread_join(threads[i], &vp);
if (rc == 0 && vp != NULL)
{
rez[i] = vp;
printf("(%s) %d ", rez[i], atoi(rez[i]));
free(rez[i]);
}
}
putchar('\n');
This passes a pointer to a void * variable to pthread_join(). If it finds the information for the requested thread, then pthread_join() makes that void * variable hold the value returned by the thread function. This can then be used as shown — note the error handling (though I note that the example in the POSIX specification for pthread_join()ignores the return value from pthread_join() with a (void) cast on the result).
I don't see where you use res or C.
The result I get is:
(21) 21 (13) 13 (63) 63 (37) 37
where the value in parentheses is a string and the value outside is converted by atoi(). That looks like the correct answer for multiplying A by B (in that order).
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
struct data
{
int p;
int linie[20];
int coloana[20];
};
static void *func(void *args)
{
struct data *st = (struct data *)args;
int c = 0;
for (int k = 0; k < st->p; k++)
{
c += st->linie[k] * st->coloana[k];
}
char *rez = (char *)malloc(5);
sprintf(rez, "%d", c);
return rez;
}
int main(void)
{
int n = 2;
int m = 2;
int A[2][2] = {{1, 2}, {4, 5}};
int B[2][2] = {{7, 3}, {7, 5}};
char *rez[n * m];
pthread_t threads[n * m];
int count = 0;
struct data st[n * m];
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
st[count].p = 2;
for (int x = 0; x < st[count].p; x++)
{
st[count].linie[x] = A[i][x];
st[count].coloana[x] = B[x][j];
}
int rc = pthread_create(&threads[count], NULL, func, &st[count]);
if (rc != 0)
{
fprintf(stderr, "Failed to create thread %d for cell C[%d][%d]\n", count, i, j);
exit(1);
}
count++;
}
}
for (int i = 0; i < n * m; i++)
{
void *vp;
int rc = pthread_join(threads[i], &vp);
if (rc == 0 && vp != NULL)
{
rez[i] = vp;
printf("(%s) %d ", rez[i], atoi(rez[i]));
free(rez[i]);
}
}
putchar('\n');
return 0;
}

Function called by pthread_create breaks when a value is assigned to the struct passed to it

am brand new to C. I have a little program which is intended to solve find the dot product of a large 2d matrix with itself using pthread. Now when the function assigned to the pthread is called and the struct passed as a variable is accessed, the program breaks and stop working. I don't really know what am doing wrong. Here is the code:
This is the main function.
int main()
{
int rc;
int threadcount = 1;
char filename[100];
//patch to enable console printing in eclipse
setvbuf(stdout, NULL, _IONBF, 0);
do {
prompt_for_fileName(filename);
if (filename[0] == 'Q' || filename[0] == 'q') {
puts("Program ended");
return 0;
}
//read thread count
read_threadcount(&threadcount);
//initialize matrices
matrix_def matrix = initialize_matrix(filename);
//get the dimension of sub-matrices
int dfRow = (int) floor(matrix.NROWS / threadcount);
pthread_t threads[threadcount];
pthread_arg pthreadargs[threadcount];
for (int i = 0; i < threadcount; i++) {
int startRow = i * dfRow;
int endRow =
((i + 1) == threadcount) ?
matrix.NROWS : (startRow + dfRow) - 1; //we're subtracting one because its zero based.
//create a structure that we'll passed to the array.
pthread_arg arg = { matrix.NROWS, matrix.NCOLS, startRow, endRow,
0.0, NULL, NULL };
arg.data = matrix.data;
arg.result_set = create_result_memory(matrix.NCOLS);
fprintf(stderr, "before %p\n", arg.result_set);
//push arg into array.
pthreadargs[i] = arg;
rc = pthread_create(&threads[i], NULL, compute_dot_product,
(void *) &arg);
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
/* Last thing that main() should do */
pthread_exit(NULL);
puts("Completed processing.");
double totalTime = 0.0;
for (int z = 0; z < threadcount; z++) {
pthread_arg ar = pthreadargs[z];
printf("Thread %d took %g to process %d rows and %d columns.\n", z,
ar.execution_time, ar.endz - ar.start, ar.col);
totalTime += ar.execution_time;
}
printf(
"It took the total time of %g, to compute the dot product of the matrices.\n",
totalTime);
//free memory
free(matrix.data);
for (int k = 0; k < threadcount; k++) {
free(pthreadargs[k].data);
free(pthreadargs[k].result_set);
}
} while (filename[0] != 'Q' || filename[0] != 'q');
}
This is the function being called by the pthread
void * compute_dot_product(void * inputArgs) {
double startTime, endTime;
pthread_arg * args = inputArgs;
/*Compute the dimension of the result matrix*/
int col, row, start, endz;
col = args->col;
start = args->start;
endz = args->endz;
row = endz - start;
fprintf(stderr, "after %p\n", args->result_set);
//create a pointer to the two array
double **arr1 = args->data;
double **arr2 = arr1;
//begin the computation
int x;
startTime = seconds();
//calculate the dot product the two matrices.
for (x = 0; x < col; x++) {
double colProduct = 0.0;
for (int y = start; y < endz; y++) {
colProduct += arr1[y][x] * arr2[y][x];
}
//The code breaks here.
args->result_set[x] = colProduct;
}
endTime = seconds();
double diff = endTime - startTime;
args->execution_time = diff;
return (void *) 4;
}
This is my struct definitions
typedef struct
{
int NROWS; /*for m rows*/
int NCOLS; /*for n columns*/
double ** data;
} matrix_def;
typedef struct
{
double execution_time;
matrix_def matrix;
} compute_result;
typedef struct{
int row;
int col;
int start;
int endz;
double execution_time;
double **data;
double *result_set;
} pthread_arg;
Memory allocation of the 2D matrix.
/*dynamically allocate array based on the read size*/
matrix.data = (double **) malloc(sizeof(double *) * M);
if(matrix.data != NULL){
int x;
for(x = 0; x < M; x++){
matrix.data[x] = (double) malloc(sizeof(double) * N);
}
}else{
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
}
Initialize Matrix function
matrix_def initialize_matrix(char *argv)
{
int ret_code;
MM_typecode matcode;
FILE *f;
int M, N, nz;
int i;
matrix_def matrix;
if((f = fopen(argv, "r")) == NULL)
{
fprintf(stderr, "Reading file: '%s' failed", argv);
exit(1);
}
/*Read matrix banner*/
if(mm_read_banner(f, &matcode) != 0)
{
printf("Could not process Matrix Market banner. \n");
exit(1);
}
/*Check if the current matrix is supported.*/
if(mm_is_complex(matcode) && mm_is_matrix(matcode) && mm_is_sparse(matcode))
{
printf("Sorry, this application does not support ");
printf("Market Matrix type: [%s]\n", mm_typecode_to_str(matcode));
exit(1);
}
/*find out size of the sparse matrix...*/
if((ret_code = mm_read_mtx_crd_size(f, &M, &N, &nz)) != 0)
exit(1);
/*Assign m, n sizes.*/
matrix.NROWS = M;
matrix.NCOLS = N;
/*dynamically allocate array based on the read size*/
matrix.data = (double **) malloc(sizeof(double *) * M);
if(matrix.data != NULL){
int x;
for(x = 0; x < M; x++){
matrix.data[x] = (double *) malloc(sizeof(double) * N);
}
}else{
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
}
/*Iterate through the created memory location and fill it with zeros*/
int a, b;
for(a = 0; a < M; a++){
for(b = 0; b < N; b++){
matrix.data[a][b] = 0;
}
}
/*Read the matrix*/
for(i = 0; i < nz; i++)
{
int I = 0, J = 0;
double val = 0;
fscanf(f, "%d %d %lg\n", &I, &J, &val);
//since the matrix market file starts off at
//1,1 we have to subtract 1 from the index
//to account for the array which starts off at
// 0,0
matrix.data[--I][--J] = val;
}
if(f != stdin)
fclose(f);
return matrix;
}
Any help will be appreciated, as am not very sure with the formula. Thanks
arg goes out of scope before the pthread is executed. Change your call to
rc = pthread_create(&threads[i], NULL, compute_dot_product, (void *) &pthreadargs[i]);
You will also need pthread_join before you exit, just in case the threads have not finished.
Edit
1) Replace your pthread_exit with
int rv;
for (i = 0; i < threadcount; ++i)
pthread_join(thread[i], &rv);
You would normally call pthread_exit inside a thread (like compute_dot_product) as an abnormal exit. This is a possible reason for your program breaking.
2) On your exit, I don't know how you have allocated your memory but this is a potential area where your code might be broken. If you have allocated your memory as
matrix.data = malloc(sizeof(double*) * matrix.NROWS);
matrix.data[0] = malloc(sizeof(double) * matrix.NROWS * matrix.NCOLS);
for (i = 1; i < matrix.NROWS; ++i)
matrix.data[i] = matrix.data[i - 1] + matrix.NCOLS;
Then you should free as
free(matrix.data[0]);
free(matrix.data);
If you have allocated each row individually, then free all the rows before freeing matrix.data.
3) Since matrix.data has been freed, pthreadargs[k].data should not be freed as it is pointing to the same area of memory that has already been freed.
The arg object defined here:
pthread_arg arg = { matrix.NROWS, matrix.NCOLS, startRow, endRow,
0.0, NULL, NULL };
goes out of scope while thread is still running. You need to prevent this from happening somehow, for example by allocating it on the heap instead.

How to handle MPI sendcount of zero

What is the correct way to handle a sendcount = 0 when using MPI_Gatherv (or any other function that requires a sendcount) when setting up the displs argument?
I have data that needs to be received by all processors, but all processors might not have any data to send themselves. As an MWE, I tried (on just two processors):
#include <stdlib.h>
#include <stdio.h>
#include <mpi.h>
int main(void)
{
int ntasks;
int thistask;
int n = 0;
int i;
int totcounts = 0;
int *data;
int *rbuf;
int *rcnts;
int *displs;
int *master_data;
int *master_displs;
// Set up mpi
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &ntasks);
MPI_Comm_rank(MPI_COMM_WORLD, &thistask);
// Allocate memory for arrays needed by allgatherv
rbuf = calloc(ntasks, sizeof(int));
rcnts = calloc(ntasks, sizeof(int));
displs = calloc(ntasks, sizeof(int));
master_displs = calloc(ntasks, sizeof(int));
// Initialize the counts and displacement arrays
for(i = 0; i < ntasks; i++)
{
rcnts[i] = 1;
displs[i] = i;
}
// Allocate data on just one task, but not others
if(thistask == 1)
{
n = 3;
data = calloc(n, sizeof(int));
for(i = 0; i < n; i++)
{
data[i] = i;
}
}
// Get n so each other processor knows about what others are sending
MPI_Allgatherv(&n, 1, MPI_INT, rbuf, rcnts, displs, MPI_INT, MPI_COMM_WORLD);
// Now that we know how much data each processor is sending, we allocate the array
// to hold it all
for(i = 0; i < ntasks; i++)
{
totcounts += rbuf[i];
}
master_data = calloc(totcounts, sizeof(int));
// Get displs for master data
master_displs[0] = 0;
for(i = 1; i < ntasks; i++)
{
master_displs[i] = master_displs[i - 1] + rbuf[i - 1];
}
// Send each processor's data to all others
MPI_Allgatherv(&data, n, MPI_INT, master_data, rbuf, master_displs, MPI_INT, MPI_COMM_WORLD);
// Print it out to see if it worked
if(thistask == 0)
{
for(i = 0; i < totcounts; i++)
{
printf("master_data[%d] = %d\n", i, master_data[i]);
}
}
// Free
if(thistask == 1)
{
free(data);
}
free(rbuf);
free(rcnts);
free(displs);
free(master_displs);
free(master_data);
MPI_Finalize();
return 0;
}
The way that I've set up master_displs works when every processor has a non-zero n (that is, they have data to send). In this case, both entries will be zero. However, the results of this program are garbage. How would I set up the master_displs array to ensure that master_data holds the correct information (in this case, just master_data[i] = i, as received from task 1)?

Conway's Game of Life, Segfault 11

I'm trying to write Conway's game of life in C. This is what I have so far. I'm using pointers to refer to the arrays, which has never caused me problems before, but the function place_cell is causing a segfault.
Here's what I've tried so far:
- I tried making the grid with constants, 100 x 100, and 10 x 10. Modifying
values inside of those constant grids still gives me a segfault.
- I tried using constants for place_cell, still got a segfault.
int** make_grid(int x, int y) {
int** is = (int**)malloc(sizeof(int*) * y);
if(! is) {
fprintf(stderr, "make_grid: malloc failed");
exit(1);
}
int j;
for(j = 0; j < y; j++) {
is[j] = (int*)malloc(sizeof(int) * x);
if(!is[j]) {
fprintf(stderr, "make_grid: malloc failed");
exit(1);
}
}
return is;
}
/* takes two integers and places a cell at those coords */
void place_cell(int** is, int sidex, int sidey, int x, int y) {
if(x >= sidex || y >= sidey) {
fprintf(stderr, "place_cell: out of grid range\n");
exit(1);
}
is[y][x] = 1;
}
int check_surroundings(int** is, int sidex,
int sidey, int x, int y) {
int y_less = y - 1;
if(y == 0) {
y_less = sidey - 1;
}
int y_more = y + 1;
if(y == sidey - 1) {
y_more = 0;
}
int x_less = x - 1;
if(x == 0) {
x_less = sidex - 1;
}
int x_more = x + 1;
if(x == sidex - 1) {
x_more = 0;
}
int p = is[y_less][x_less] +
is[y_less][x] +
is[y_less][x_more] +
is[y][x_less] +
is[y][x_more] +
is[y_more][x_less] +
is[y_more][x_less] +
is[y_more][x_more];
return p;
}
void change_condition(int** is,
int sidex, int sidey, int x, int y) {
int* state = &is[y][x];
int surr = check_surroundings(is, sidex, sidey, x, y);
if(surr > 3) {
*state = 0;
} else if(surr == 3 || surr == 2) {
*state = 1;
} else {
*state = 0;
}
}
void print_grid(int** is, int sidex, int sidey) {
int i, j;
for(i = 0; i < sidey; i++) {
for(j = 0; j < sidex; j++) {
if(is[i][j] == 1) {
printf("*");
} else {
printf(" ");
}
}
printf("\n");
}
}
void new_generation(int** is, int sidex, int sidey) {
int i, j;
for(i = 0; i < sidey; i++) {
for(j = 0; j < sidex; j++) {
change_condition(is, sidex, sidey, j, i);
}
}
}
void play(int** is, int sidex, int sidey) {
int i = 0;
while(i < 100) {
new_generation(is, sidex, sidey);
print_grid(is, sidex, sidey);
i++;
}
}
here's my main:
int main(int argc, char* argv[]) {
int sidex = atoi(argv[0]);
int sidey = atoi(argv[1]);
int** is = make_grid(10, 10);
int i;
for(i = 2; i < argc; i += 2) {
place_cell(is, sidex, sidey,
atoi(argv[i]), atoi(argv[i + 1]));
}
return 0;
}
edit:
int** make_grid(int x, int y) {
int (*is)[x] = (int*)malloc(sizeof(int) * y * x);
if(! is) {
fprintf(stderr, "make_grid: malloc failed");
exit(1);
}
int j;
for(j = 0; j < y; j++) {
is[j] = (int*)malloc(sizeof(int) * x);
if(!is[j]) {
fprintf(stderr, "make_grid: malloc failed");
exit(1);
}
}
return is;
}
This isn't right at all but I can't put my finger on why. Can someone explain to me what to change like I'm five? (a five year-old who knows C, I guess)
I just copied your entire code and tried to run the program. The memory access violation (at least for me) is in this line:
int sidex = atoi(argv[0]);
int sidey = atoi(argv[1]); <-- memory access violation
The reason is (in my case at least) that I just ran the program with no arguments.
Now, even if I did provide the arguments on the command line the indexing is still off. The first argument argv[0] is the name of the executable, not the first argument after the name.
So, a few things to note for your code:
It is not guaranteed that there will be arguments. You should always check the argc to make sure you can index into argv
Those arguments are not guaranteed to be integer numbers either - you better check for that too, before you use them as your dimensions
Of course with the indexing shift you should adjust for your "array reading" code accordingly as well. But once you fix the indexing this should be an easy one for you
You are not declaring a two-dimensional array with that syntax, so the memory is not aligned the way you think, thus a segmentation fault. Declaring a pointer int** does not make it a 2-D array. (Surely you don't think int *** would get you a data cube ?).
Heap allocate a 2D array (not array of pointers)
One of the comments above gives the other problem, the zero parameter to a C program argv[0] is the name of the program, not the first parameter on the command line, that is argv[1].

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);

Resources