I'm new to C and have been trying to tackle this question. It's a continuation of the last thread I made. I made some progress but still have so much to learn and fix.
In short:
In this question a "vector" is a one dimensional array of integers. Therefore an array of vectors would be a two dimensional array that holds one dimensional arrays inside him.
I need to use these variables:
int** vectors- the 2D array
int size -an integer that represents how many vectors exist inside **vectors
int* sizes-a 1D array of integers that represents the length of the vectors
I need to write the following functions:
int init(int ***vectors, int **sizes, int size)
the function allocated memory to **vectors and *sizes with size and initializes vectors to be full of NULLs,and sizes to be full of zeros.
int set(int **vectors, int *sizes, int index, int *tmp, int tmp_size)
the function receives an array of nulls (**vectors)), frees the vector inside **vectors whose index is index and allocates memory for a new vector, whose length is tmp_size and places inside it *tmp's elements.
This is my code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int init(int*** vectors, int** sizes, int size)
{
int i, k,j;
*sizes = (int*)malloc(size * sizeof(int));
if (*sizes == NULL)
return 0;
for (j = 0; j < size; j++)
{
(*sizes)[j] = 0;
}
*vectors = (int**)malloc(size * sizeof(int*));
if (*vectors == NULL)
return 0;
for (i = 0; i < size; i++)
{
(vectors)[i] = NULL;
}
return 1;
}
int set(int **vectors, int *sizes, int index, int *tmp, int tmp_size)
{
if ((vectors)[index] != NULL)
{
free((vectors)[index]);
}
(vectors)[index] = (int*)malloc(tmp_size * sizeof(int));
if ((vectors)[index] == NULL)
return 0;
for (int b = 0; b < tmp_size; b++)
{
(vectors)[index][b] = tmp[b];
}
sizes[index] = tmp_size;
return 1;
}
int main()
{
int size, i, length, indexhere;
int** vectors = NULL;
int* sizes = NULL;
int* tmp = NULL;
int* p = &vectors;
int tempindex;
printf("\nPlease enter an amount of vectors:\n");
scanf("%d", &size);
init(p, &sizes, size);
printf("Enter index\n");
scanf("%d", &indexhere);
printf("Enter Length\n");
scanf("%d", &length);
tmp = (int*)malloc(length * sizeof(int));
printf("Enter elements:\n");
for (int g = 0; g < length; g++)
scanf("%d", &tmp[g]);
set(&vectors, sizes, indexhere, tmp, length);
system("pause");
return 0;
}
Could someone explain please why the program always crashes?
In init function (vectors)[i] = NULL; should actually be (*vectors)[i] = NULL;
When calling set function from main you should pass vectors instead of &vectors.
There also seems to be several pointer type mismatches in your code, so you should really pay attention to compiler's warnings. This is because C unfortunately allows implicit conversions between incompatible pointers, unlike C++ for example.
You call set like this
set(&vectors, sizes, indexhere, tmp, length);
but the first argument is declared as an int **. By passing &vector you're passing a pointer to vector, i.e. something of type int ***. This mismatch will lead to undefined behavior and probable crashes.
Here is a complete working example.
#include <stdio.h>
#include <stdlib.h>
void destroyVectors(int **vectors, int size)
{
for (int i = 0; i < size; i++)
{
free(vectors[i]);
}
}
int init(int*** vectors, int** sizes, int size)
{
int i, j;
*sizes = (int*)malloc(size * sizeof(int));
if (*sizes == NULL)
return 0;
for (j = 0; j < size; j++)
{
(*sizes)[j] = 0;
}
*vectors = (int**)malloc(size * sizeof(int*));
if (*vectors == NULL)
return 0;
for (i = 0; i < size; i++)
{
(*vectors)[i] = NULL;
}
return 1;
}
int set(int **vectors, int *sizes, int index, int *tmp, int tmp_size)
{
if ((vectors)[index] != NULL)
{
free((vectors)[index]);
}
(vectors)[index] = (int*)malloc(tmp_size * sizeof(int));
if ((vectors)[index] == NULL)
return 0;
for (int b = 0; b < tmp_size; b++)
{
(vectors)[index][b] = tmp[b];
}
sizes[index] = tmp_size;
return 1;
}
int main()
{
int size = 0, length = 0, indexhere = 0;
int** vectors = NULL;
int* sizes = NULL;
int* tmp = NULL;
printf("\nPlease enter an amount of vectors:\n");
scanf("%d", &size);
init(&vectors, &sizes, size);
printf("Enter index\n");
scanf("%d", &indexhere);
printf("Enter Length\n");
scanf("%d", &length);
tmp = (int*)malloc(length * sizeof(int));
printf("Enter elements:\n");
for (int g = 0; g < length; g++)
scanf("%d", &tmp[g]);
set(vectors, sizes, indexhere, tmp, length);
for(int i = 0; i < length; ++i)
printf("byte: %d\n", vectors[indexhere][i]);
printf("sizes index: %d\n", sizes[indexhere]);
free(tmp);
free(sizes);
destroyVectors(vectors, size);
return 0;
}
Related
I have been given a school assignment in C to create a program that multiplies matrices. I will list assignment constraints below so people don't respond with questions as to why I am doing things this way.
Constraints from instructor:
Cannot use square brackets anywhere in code (use pointer notation instead)
Matrices A, B, C must be single integer pointer variables (int *A, *B, *C)
Can only use main function and those specified by header
Must compile with "gcc -ansi -Wall -o p2 p2.c"
I have not implemented the matrix multiplication function yet, as the issues I am having relate to either file reading or memory allocation.
The specific problem I am having is when I allocate space to the pointer matrix with either malloc OR calloc (tried both), the program inserts 33 in some places in the output instead of 0. I've tried everything at this point and am convinced my knowledge of pointers is fundamentally flawed.
p2.h (given by instructor)
#include <stdio.h>
#include <stdlib.h>
/* This function reads m, n, and p from the datafile.
It then allocates the correct amount of memory required for matrices
A, B, and C.
Then matrices A and B are filled from the datafile.
The values for m, n, and p are passed by reference, and are
thus filled in by this function
PARAMETERS in order are:
int ** matrix A
int ** matrix B
int ** matrix C
int * m The number of rows in matrix A
int * n The number of columns in matrix A and
The number of rows in matrix B
int * p The number of columns in matrix B
char * The name of the datafile, from the command line
*/
void read_matrices(int **, int **, int **, int *, int *, int *, char *);
/* This function prints a matrix. Rows and columns should be preserved.
PARAMETERS in order are:
int * The matrix to print
int The number of rows in the matrix
int The number of columns in the matrix
*/
void print_matrix(int *, int, int);
/* The two matrices A and B are multiplied, and matrix C contains the
result.
PARAMETERS in order are:
int * Matrix A
int * Matrix B
int * Matrix C
int m
int n
int p
*/
void mult_matrices(int *, int *, int *, int, int, int);
p2.c (sorry for the mess a lot of debugging went on)
#include <stdio.h>
#include <stdlib.h>
#include "./p2.h"
/* constants for testing */
#define cM 3
#define cN 2
#define cP 5
int main(int argc, char **argv) {
if (argc < 2) {
printf("Must include an argument.\n");
exit(1);
}
char *path = *(argv + 1);
int *m = (int *) malloc(sizeof(int));
int *n = (int *) malloc(sizeof(int));
int *p = (int *) malloc(sizeof(int));
*m = cM; *n = cN; *p = cP;
int i,j; /* loop counters */
/* allocate space for 2d pointer arrays */
int **A = NULL;
A = (int **) malloc(*m * sizeof(int *));
for (i = 0; i < *m; i++) {
*(A+i) = (int *) malloc(*n * sizeof(int));
}
int **B = NULL;
B = (int **) malloc(*n * sizeof(int *));
for (i = 0; i < *n; i++) {
*(B+i) = (int *) malloc(*p * sizeof(int));
}
int **C = NULL;
C = (int **) malloc(*m * sizeof(int *));
for (i = 0; i < *m; i++) {
*(C+i) = (int *) malloc(*p * sizeof(int));
}
/* write data to A */
for (i = 0; i < *m; i++) {
for (j = 0; j < *n; j++) {
*(*(A+i)+j) = 0;
}
}
/* testing a */
for (i = 0; i < *m; i++) {
for (j = 0; j < *n; j++) {
if (*(*(A+i)+j) != 0) {
printf("[x]");
} else {
printf("[0]");
}
}
}
printf("\n");
/* write data to B */
for (i = 0; i < *n; i++) {
for (j = 0; j < *p; j++) {
*(*(B+i)+j) = 0;
}
}
/* testing b */
for (i = 0; i < *n; i++) {
for (j = 0; j < *p; j++) {
if (*(*(B+i)+j) != 0) {
printf("[x]");
} else {
printf("[0]");
}
}
}
printf("\n");
/* write data to C */
for (i = 0; i < *m; i++) {
for (j = 0; j < *p; j++) {
*(*(C+i)+j) = 0;
}
}
/* testing c */
for (i = 0; i < *m; i++) {
for (j = 0; j < *p; j++) {
if (*(*(C+i)+j) != 0) {
printf("[x]");
} else {
printf("[0]");
}
}
}
printf("\n");
printf("Matrix A: \n");
print_matrix(*A, *m, *n);
printf("Matrix B: \n");
print_matrix(*B, *n, *p);
printf("Matrix C: \n");
print_matrix(*C, *m, *p);
return 0;
}
void read_matrices(int **A, int **B, int **C, int *m, int *n, int *p, char *path) {
FILE *fptr;
fptr = fopen(path, "r");
if (fptr == NULL) {
printf("Cannot open file: ./p2 [filename].txt\n");
exit(1);
}
/* get first 3 numbers from file, set m,n,p */
*m = fgetc(fptr);
fgetc(fptr);
*n = fgetc(fptr);
fgetc(fptr);
*p = fgetc(fptr);
fgetc(fptr);
/* read first matrix */
/* 1) calculate matrix size m x n
* 2) loop through malloc'ed matrix
* 3) each loop, insert char in loc
* 4) if next char NOT 10/32, add nextchar*10 to value in loc
*/
char cur;
while ( (cur = fgetc(fptr)) != EOF ) {
if (cur == 10 || cur == 32) {
/* do nothing :) */
} else {
*m = cur;
*n = cur;
*p = cur;
break;
}
}
printf("m: %c\n", *m);
printf("n: %c\n", *n);
printf("p: %c\n", *p);
printf("next: %c\n", fgetc(fptr));
fclose(fptr);
}
void print_matrix(int *X, int rows, int cols) {
int r, c;
int k = 0;
for (r = 0; r < rows; r++) {
for (c = 0; c < cols; c++) {
printf("\t%d", *(X+k));
k++;
}
printf("\n");
}
}
void mult_matrices(int *A, int *B, int *C, int m, int n, int p) {
}
d2.txt (data file)
3
2
4
1 2
3 4
5 6
7 8 9 10
11 12 13 14
Output: ./p2 d2.txt
[0][0][0][0][0][0]
[0][0][0][0][0][0][0][0][0][0]
[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]
Matrix A:
0 0
0 0
0 0
Matrix B:
0 0 0 0 0
0 33 0 0 0
Matrix C:
0 0 0 0 0
0 33 0 0 0
0 0 0 0 33
If you notice, I have some debug code that checks whether or not the current item in the array is 0. It seems to indicate that they are all 0, making me think it is a printing problem, but I am even more lost on what would be causing that. The ascii code for 33 is an exclamation point, but I am not sure what relevance it has.
Based on the function signatures you're supposed to use, you need to implement your 2D arrays as 1D with the correct index math. This will result in all memory being laid out contiguously, which is not at all guaranteed with the way you're allocating memory now (two calls to malloc for each matrix). For example:
#include <stdio.h>
#include <stdlib.h>
void print_matrix(int* A, int rows, int cols)
{
for (int r=0; r<rows; r++)
{
for (int c=0; c<cols; c++)
{
// If you want to treat A as a 2D matrix, this is where we have to do a bit of
// fancy index math to give you what double bracket notation [][] does for you
// r * cols gives you the index of the right row
// + c give you the column offset in that row
// add that offset to A then dereference
printf("%d\t", *(A + (r * cols + c)));
}
printf("\n");
}
}
int main(void)
{
// matrix A is supposed to be m by n
int* A;
// read these from file, or where ever they're supposed to come from
int m = 2;
int n = 10;
// Allocate the memory in one chunk. This makes the memory all contiguous, just the
// same as if you had done A[m][n]. However, the double call malloc for each int**
// matrix probably will not give you contiguous memory for the entire matrix. Each
// call to malloc is independent.
A = malloc(m * n * sizeof(int)); // or sizeof(*A) would be even better
if (A == NULL)
{
// handle error
}
// We can initialize values for A at this point, still not needing to care about
// rows or columns
for (int i=0; i<m*n; i++)
{
*(A + i) = i; // using i for a better visual when we print
}
print_matrix(A, m, n);
free(A);
return 0;
}
Demo
You are ovecomplicating simple things. Use pointers to arrays and allocate 2D array.
Use the correct type of your size variables.
Try to avoid side effects. Use parameters and function return values.
//this function is for the test purposes only
int writefile(const char *fn)
{
FILE *fo = fopen(fn, "w");
fprintf(fo,
"3\n"
"2\n"
"4\n"
"1 2\n"
"3 4\n"
"5 6\n"
"7 8 9 10\n"
"11 12 13 14\n");
fclose(fo);
}
void *allocIntMatrix(size_t rows, size_t cols)
{
int (*m)[cols] = malloc(rows * sizeof(*m));
return m;
}
void printIntMatrix(size_t rows, size_t cols, int (*m)[cols])
{
for(size_t row = 0; row < rows; row++)
{
for(size_t col = 0; col < cols; col++)
{
printf("[%5d] ", m[row][col]);
}
printf("\n");
}
}
int readData(FILE *fi, size_t rows, size_t cols, int (*m)[cols])
{
for(size_t row = 0; row < rows; row++)
{
for(size_t col = 0; col < cols; col++)
{
fscanf(fi, "%d", &m[row][col]);
}
}
return 0;
}
int main(int argc, char **argv)
{
size_t n,m,p;
writefile("a.aaa");
FILE *fi = fopen("a.aaa", "r");
fscanf(fi, "%zu", &m);
fscanf(fi, "%zu", &n);
fscanf(fi, "%zu", &p);
printf("n = %zu, m = %zu, p = %zu\n", n, m, p);
int (*A)[n] = allocIntMatrix(m, n);
int (*B)[p] = allocIntMatrix(n, p);
readData(fi, m, n, A);
readData(fi, n, p, B);
fclose(fi);
printIntMatrix(m, n, A);
printf("\n");
printIntMatrix(n, p, B);
return 0;
}
https://godbolt.org/z/adoEx1r4f
You need to check for errors (file, memory etc). I skipped it for the sake of simplicity of the example.
#include <stdio.h>
#include <stdlib.h>
struct arrayADT {
int *A;
int size;
int length;
int *B;
int arr3;
};
struct arrayADT * MergeArray(struct arrayADT *arr1, struct arrayADT *arr2) { //we create thus in heap cuz we need to be able to use these in main function
struct arrayADT *arr3 = (struct arrayADT *)malloc((sizeof(struct arrayADT)));
int i, j, k;
i = j = k = 0;
while(i < arr1->length && j < arr1->length ) {
if(arr1->A[i] < arr2->A[j]) {
arr3->A[k] = arr1->A[i];
k++;
i++;
}
else {
arr3->A[k] = arr2->A[j];
k++;
j++;
}
}
for(; i<arr1->length ; i++) {
arr3->A[k] = arr1->A[i];
k++;
}
for(; j < arr2->length ; j++) {
arr3->A[k] = arr2->A[j];
k++;
}
arr3->length = arr1->length + arr2->length;
arr3->length = 10;
}
void main() {
struct arrayADT arr;
printf("Enter the size of an array");
scanf("%d", &arr.size);
arr.A = (struct arrayADT *)malloc(arr.size * sizeof(int));
arr.length = 0;
int n;
printf("enter the number of elements in an array");
scanf("%d", &n);
printf("enter the elements");
for(int i = 0; i < n; i++) {
scanf("%d", &arr.A[i]);
}
arr.length = n;
display(arr);
printf("Enter second array");
int j;
struct arrayADT *B = (struct arrayADT *)malloc((sizeof(struct arrayADT)));
for(j = 0; j < arr.length; j++) {
scanf("%d", &B[j]);
}
struct arrayADT *arr3 = (struct arrayADT *)malloc(sizeof(struct arrayADT));
arr3 = MergeArray(&arr, &B);
display(*arr3);
I was looking to merge these arrays using heap memory and I am getting segmentation fault. I am new to C programming with pointers and I have been struck here it would be so helpful if I passed this barrier with your help.
And I am not getting where my error lies it would be helpful if someone specifies that too, so that I can avoid these errors in future.
PS: I am using minGW compiler.
In general, your code is rater unorganized. There are several cases for undefined behaviour, for example you don't scan in the second array correctly. The most probably candidate for your segmentaion fault is here:
struct arrayADT *arr3 = (struct arrayADT *)malloc((sizeof(struct arrayADT)));
This will give you an uninitialized chunk of memory. The length and size could of arr3 be anything, and its data field A does not point to valid memory. Accessing it will likely crash.
You have three arrays in your code. You construct each step by step and you treat each differently. That leads to errors easily. Let's go about this more systematically.
Let's create a struct type for a fixed-size array: The maximum size must be given on creation and cannot change. The actual length of the array may be anything from 0 to its maximum size.
typedef struct Array Array;
struct Array {
int *value; // data array
int length; // actual length, 0 <= length <= size
int size; // maximum capacity
};
We create such arrays on the heap and because initializing the members is error-prone, we write a constructor:
Array *array_create(int size)
{
Array *array = calloc(1, sizeof(*array));
array->size = size;
array->value = calloc(size, sizeof(*array->value));
return array;
}
This function creates an empty array for at most size integers. If we allocate memory, we must de-allocate it later, so let's write a corresponding destructor function, which cleans up the ressources:
void array_destroy(Array *array)
{
if (array) {
free(array->value);
free(array);
}
}
After destroying an array, it can no longer be used, just as with memory after calling free() on it.
The array is at first empty, so let's write a function to add elements at its end if there is room:
void array_push(Array *array, int x)
{
if (array->length < array->size) {
array->value[array->length++] = x;
}
}
And a function to print it:
void array_print(const Array *array)
{
printf("[");
for (int i = 0; i < array->length; i++) {
if (i) printf(", ");
printf("%d", array->value[i]);
}
printf("]\n");
}
Now you can create arrays like so:
Array *a = array_create(10);
for (int i = 0; i < a->size; i++) {
array_push(a, i);
}
array_print(a);
array_destroy(a);
Your merge function will be simpler, too. Here's a full example. (But is uses generated array, not arrays typed in by the user.)
#include <stdio.h>
#include <stdlib.h>
typedef struct Array Array;
struct Array {
int *value;
int length;
int size;
};
Array *array_create(int size)
{
Array *array = calloc(1, sizeof(*array));
array->size = size;
array->value = calloc(size, sizeof(*array->value));
return array;
}
void array_destroy(Array *array)
{
if (array) {
free(array->value);
free(array);
}
}
void array_push(Array *array, int x)
{
if (array->length < array->size) {
array->value[array->length++] = x;
}
}
void array_print(const Array *array)
{
printf("[");
for (int i = 0; i < array->length; i++) {
if (i) printf(", ");
printf("%d", array->value[i]);
}
printf("]\n");
}
Array *merge(Array *a, Array *b)
{
Array *res = array_create(a->length + b->length);
int i = 0;
int j = 0;
while(i < a->length && j < b->length) {
if(a->value[i] < b->value[j]) {
array_push(res, a->value[i++]);
} else {
array_push(res, b->value[j++]);
}
}
while(i < a->length) {
array_push(res, a->value[i++]);
}
while(j < b->length) {
array_push(res, b->value[j++]);
}
return res;
}
int main(void)
{
Array *a = array_create(10);
Array *b = array_create(6);
Array *c;
for (int i = 0; i < a->size; i++) {
array_push(a, 1 + 3 * i);
}
for (int i = 0; i < b->size; i++) {
array_push(b, 4 + 2 * i);
}
array_print(a);
array_print(b);
c = merge(a, b);
array_print(c);
array_destroy(a);
array_destroy(b);
array_destroy(c);
return 0;
}
If you've read so far, here's the lowdown:
Organzie your code. That applies to code layout as much as writing small, generally applicable functions instead of doing everything "by hand". (The array type above is a bit on the fence: It uses functions, but getting at the data is still done via accessing the struct fields. You could even change the szie and length, whixh shouldn't really happen.)
Enable compiler warnings with -Wall. You will get useful information about potential (and often actual) errors.
Good luck!
I am new to threads and I have a program that uses threads to find the minimum number out of a 2d array and later on, it finds the distance that the other elements of the array have from the minimum number and stores them in another array.
The user should enter the size of the array and the number of threads he wants to use.
I tried the program below for 1d array and it worked just fine. When I converted it to work for a 2d array it started crashing and throwing a segmentation fault. I, however, cannot find which part of the 2d declaration is wrong.
Any help is really appreciated.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <pthread.h>
struct Parameters
{
// input
int s,p; //n is size of array, p is number of threads
int** array; //array with elements
int start;
int end;
// output
int smallest;
int pos; //position if minimum
int** B; //array that holds the distances
};
void* min(void* args)
{
struct Parameters* p = (struct Parameters*)args;
int **array = p->array;
int **B1 = p->B;
int start = p->start;
int end = p->end;
int smallest = array[start][start];
int pos = p->pos;
int distance;
//find the smallest
for (int i = start; i < end; i++)
{
for(int j = start; j < end; j++)
{
if (array[i][j] < smallest)
{
smallest = array[i][j];
pos = i;
}
}
}
//find the distances
for(int i = 0; i < ((struct Parameters*)args) -> s; i++)
{
for(int j = 0; j < ((struct Parameters*)args) -> s; j++)
{
distance = abs(pos - i);
B1[i][j] = distance;
}
}
params->smallest = smallest;
params->B = B1;
return NULL;
}
int main()
{
int smallest,pos;
int s,p;
struct Parameters *ptr = (struct Parameters *)malloc(sizeof(struct Parameters));
if(ptr == NULL)
{
printf("Not enough. Try again \n");
exit(0);
}
printf("Type s\n");
scanf("%d",&(ptr->s));
printf("Type p\n");
scanf("%d", &(ptr->p));
// declare an array of threads and associated parameter instances
pthread_t threads[(ptr->p)];
struct Parameters thread_parameters[(ptr->p)] ;
int arr[ptr->s][ptr->s];
int B2[ptr->s][ptr->s];
// intialize the array
for(int i=0; i< ptr->s; i++)
{
for(int j=0; j< ptr->s; j++)
{
printf("Type a \n");
scanf("%d",&arr[i][j]);
}
}
// smallest needs to be set to something
smallest = arr[0][0];
// start all the threads
for (int i = 0; i < ptr->p; i++)
{
memcpy(arr, thread_parameters[i].array, sizeof(arr));
thread_parameters[i].s = ptr->s;
memcpy(Bb, thread_parameters[i].B, sizeof(B2));
thread_parameters[i].start = i * (ptr->s / ptr->p);
thread_parameters[i].end = (i+1) * (ptr->s / ptr->p);
pthread_create(&threads[i], NULL, min, &thread_parameters[i]);
}
// wait for all the threads to complete
for (int i = 0; i < ptr->p; i++)
{
pthread_join(threads[i], NULL);
}
// Now aggregate the "smallest" and "largest" results from all thread runs
for (int i = 0; i < ptr->p; i++)
{
if (thread_parameters[i].smallest < smallest)
{
smallest = thread_parameters[i].smallest;
}
}
printf("Smallest is %d\n", smallest);
thread_parameters[ptr->p].B[ptr->s][ptr->s];
for (int i = 0; i < 1; i++)
{
for(int j = 0; j < ptr->s;j++)
{
for(int k = 0; k < ptr->s; k++)
{
printf("Element %d is %d away from min\n",j,thread_parameters[i].B[j][k]);
}
}
}
return 0;
}
Thank you!!
The issue with your code might also come from :
memcpy(arr, thread_parameters[i].array, sizeof(arr));
...
memcpy(Bb, thread_parameters[i].B, sizeof(B2));
as thread_parameters[i].array and thread_parameters[i].B are not allocated, if you are only reading the array it might b fine to only pass them by address
thread_parameters[i].array = arr
but for thread_parameters[i].B you would need to allocate the arrays and perform a deep copy (memcpy would not work)
The below text does not answer the question but does provide some insight on VLA usage
One reason for causing the segmentation with a declaration of a Variable Length Array is that the value is to large to allocate the array on the stack (some compiler choose this option, this choice might have performance reason).
The is not much option to recover cleanly from failure to allocate memory on the stack as there is little way to clean up stack memory during runtime within the same stack context.
You can mitigate the issue by allocating your 2D arrays on the heap instead, some of the strategies are available here(thanks #Lundin) and here.
int** alloc_2d_int_array(size_t rows, size_t cols) {
int **result = malloc(rows * sizeof(int *));
if(result == NULL) {
// could not allocate more memory
return NULL;
}
size_t row_size = cols * sizeof(int);
for(int i=0; i < rows; ++i) {
result[i] = malloc(row_size);
if(result[i] == NULL) {
// could not allocate more memory
// cleanup
return NULL;
}
}
return result;
}
the above implementation have not been tested, but does compile, there are still risk of integer overflow.
Then use the above define function as following:
int **arr = alloc_2d_int_array(ptr->s, ptr->s);
int **B2 = alloc_2d_int_array(ptr->s, ptr->s);
easier implementation (see here(thanks #Lundin))
int **arr = malloc(sizeof(int[ptr->s][ptr->s]);
int **B2 = malloc(sizeof(int[ptr->s][ptr->s]);
I'm writing counting sort in C. N is the number of elements in table which is to be sorted, k is max value that any of this element can be. However, this code, leaves me with the same table as the input. What's wrong?
void countingSort(int *tab, int n, int k) {
int *counters = (int *)malloc(k * sizeof(int));
int *result = (int *)malloc(n * sizeof(int*));
for (int i = 0; i < k; i++) {
counters[i] = 0;
}
for (int i = 0; i < n; i++) {
counters[tab[i]]++;
}
int j = 0;
for (int i = 0; i < k; i++) {
int tmp = counters[i];
while (tmp--) {
result[j] = i;
j++;
}
}
tab = result;
}
There are some problems in your code:
int *result = (int *)malloc(n * sizeof(int*)); uses an incorrect size. The array element type is int, not int*. You should write:
int *result = (int *)malloc(n * sizeof(int));
or better:
int *result = (int *)malloc(n * sizeof(*result));
note also that the cast is useless in C, unlike C++ where it is mandatory:
int *result = malloc(n * sizeof(*result));
you could avoid the extra initializing loop by using calloc():
int *counters = calloc(n, sizeof(*counters));
a major problem: the result array is never returned to the caller: tab = result; just modifies the argument value, not the caller's variable. You should instead use the tab array to store the results directly.
you do not free the arrays, causing memory leaks.
you do not test for allocation success, causing undefined behavior if memory is not available. You should return an error status indicating this potential problem.
Here is a corrected version:
// assuming all entries in tab are > 0 and < k
int countingSort(int *tab, int n, int k) {
int *counters = calloc(k, sizeof(*counters));
if (counters == NULL)
return -1;
for (int i = 0; i < n; i++) {
counters[tab[i]]++;
}
int j = 0;
for (int i = 0; i < k; i++) {
int tmp = counters[i];
while (tmp--) {
tab[j++] = i;
}
}
free(counters);
return 0;
}
You pass tab to the function by pointer. However you need to change not the value, but address of the variable. So you should pass address of the pointer to countingSort.
void countingSort(int **tab, int n, int k)
All the solutions I have seen online has calloc() function used twice, is it possible to do with only using it once?
The below code is not printing the correct array elements
int **ptr;
//To allocate the memory
ptr=(int **)calloc(n,sizeof(int)*m);
printf("\nEnter the elments: ");
//To access the memory
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
scanf("%d",ptr[i][j]);
}
}
Since C99 you can use pointers to VLAs (Variable Length Arrays):
int n, m;
scanf("%d %d", &n, &m);
int (*ptr)[m] = malloc(sizeof(int [n][m]));
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
scanf("%d", &ptr[i][j]); // Notice the address of operator (&) for scanf
}
}
free(ptr); // Call free only once
If it's just about minimising the number of calls to memory allocation functions you can created such a jagged array like this:
#include <stdlib.h>
#include <stdio.h>
int ** alloc_jagged_2d_array_of_int(size_t n, size_t m)
{
int ** result = NULL;
size_t t = 0;
t += n * sizeof *result;
t += n*m * sizeof **result;
result = calloc(1, t);
if (NULL != result)
{
for (size_t i = 0; i < n; ++i)
{
result[i] = ((int*) (result + n)) + i*m;
}
}
return result;
}
Use it like this:
#include <stdlib.h>
#include <stdio.h>
int ** alloc_jagged_2d_array_of_int(size_t, size_t);
int main(void)
{
int result = EXIT_SUCCESS;
int ** p = alloc_jagged_2d_array_of_int(2, 3);
if (NULL == p)
{
perror("alloc_jagged_2d_array_of_int() failed");
result = EXIT_FAILURE;
}
else
{
for (size_t i = 0; i < 2; ++i)
{
for (size_t j = 0; j < 3; ++j)
{
p[i][j] = (int) (i*j);
}
}
}
/* Clean up. */
free(p);
return result;
}