Accessing array malloced inside a function from outside - unexpected results - c

I have a function designed to malloc an array and then fill it with values from a file (n-dimensional coordinates, although working in 2d for now).
#include <stdio.h>
#include <stdlib.h>
#define dim 2
typedef struct {
double **array; /*store the coordinates*/
int num; /* store the number of coordinates*/
/* store some other things too */
} foo;
void read_particles(foo *bar);
int main(void)
{
foo bar;
read_particles(&bar);
printf("\n");
for(int i = 0; i < bar.num; i++)
printf("%f %f\n", bar.array[0][i], bar.array[1][i]);
/* printf here does not output the array properly.
* Some values are correct, some are not.
* Specifically, the first column bar.array[0][i] is correct,
* the second column bar.array[1][i] is not, some values from the
* first column are appearing in the second.
*/
return 0;
}
void read_particles(foo *bar)
{
FILE *f = fopen("xy.dat", "r");
/* read number of coordinates from file first*/
fscanf(f, "%d", &bar->num);
bar->array = (double**) malloc(bar->num * sizeof(double*));
for(int i = 0; i < bar->num; i++)
bar->array[i] = (double*) malloc(dim * sizeof(double));
for(int i = 0; i < bar->num; i++)
{
for(int j = 0; j < dim; j++)
fscanf(f, "%lf", &(bar->array[j][i]));
/* For now, coordinates are just 2d, print them out
* The values are displayed correctly when printing here*/
printf("%f %f\n", bar->array[0][i], bar->array[1][i]);
}
fclose(f);
}
Some sample data is available here.
When the values are printed from inside the function they are fine, when printed outside the function they are not. So I must not be dealing with the pointers properly. It may (or may not) be worth noting that I originally was not using a struct and had the function defined as double **read_and_malloc(num), returning the pointer to the array, and the output produced was identical.
So what is going on?
I can include some sample data, or any other information if need be.

Your second loop is not correct:
for(int i = 0; i < dim; i++)
bar->array[i] = (double*) malloc(dim * sizeof(double));
You create bar->num elements yet you iterate over dim elements:
bar->array = (double**) malloc(bar->num * sizeof(double*))
The loop should iterate over the number of elements in the first dimension: bar->num

In the updated code you are allocating bar->num rows and 2 columns. However, your fscanf and printf code tries to work on array with 2 rows and bar->num columns.
To keep your reading/writing code intact, the allocation code would be:
bar->array = malloc(dim * sizeof *bar->array);
for (int i = 0; i < dim; ++i)
bar->array[j] = malloc(bar->num * sizeof *bar->array[j]);
NB. If you're not familiar with this malloc idiom, see here

Related

Segmentation fault using scanf for float ** type

I'm trying to code a function that would ask the user to enter matrix. It prompts the number of lines, the number of columns and then prompts the value for each element of the matrix:
#include <stdio.h>
#include <stdlib.h>
void enterMatrix(float ** matrix, int nbLines, int nbColumns){
for (int i = 0; i < nbLines * nbColumns; i++){
printf("i = %d? ", i);
scanf("%f", matrix[i]);
}
}
int main(void){
int nbLines, nbColumns;
printf("nbLines? "); scanf("%d", &nbLines);
printf("nbColumns? "); scanf("%d", &nbColumns);
float *matrix[nbL * nbCol];
enterMatrix(matrix, nbLines, nbColumns);
}
Everything works fine until I enter a value for i = 0 and then press enter, which leads to a segmentation fault.
Any idea as to what could be wrong?
Your problem is because
float *matrice[nbL * nbCol];
defines an array of uninitialised pointers (i.e. an array of float *), not an array of float. This is then passed to enterMatrix() as a pointer to pointer to float (i.e. a float **). The scanf() calls then read to matrix[i] which is an uninitialised pointer. The result is undefined behaviour.
One fix would be to change the definition of matrice in main() to
float matrice[nbL * nbCol];
and change the function to (I've used comment to highlight changes)
void enterMatrix(float *matrix, int nbLines, int nbColumns) /* note type of matrix */
{
for (int i = 0; i < nbLines * nbColumns; i++)
{
printf("i = %d? ", i);
scanf("%f", &matrix[i]); /* note what the second argument is */
}
}
You need to allocate memory dinamically since you do not know at compile time which values the variables nbLines and nbColumns will hold.
So you need to first declare the pointer to the matrix:
float **matrix;
Then start allocate memory according to user input:
matrix = (float **)malloc(nbLines * sizeof(float *));
for (int i = 0; i < nbLines; i++)
{
matrix[i] = (float *)malloc(nbColums * sizeof(float ));
}
The segmentation fault error happens becouse you are not allocating memory for your matrix, but just a [nbL * nbCol] pointers to float
You don't allocate enough memory for your array, thus you invoke Undefined Behavior, since you go out of bounds, causing a Segmentation fault.
You could declare it like a 2D array, like this:
/* TODO: Check if allocation succeeded. (check for NULL pointer) */
float** matrix;
matrix = malloc(nbLines * sizeof(float*));
for(int i = 0 ; i < N ; i++)
matrix[i] = malloc(nbColumns * sizeof(float));
I have other approaches for allocating a 2D array dynamically here.
Please note: Do I cast the result of malloc? No!
Also do not forget to free().
You could emulate a 2D array with an 1D array, like this:
void enterMatrix(float* matrix, int nbLines, int nbColumns){
for (int i = 0; i < nbLines ; i++) {
for (int j = 0; j < nbColumns; j++) {
scanf("%f", matrix[i + nbColumns * j]);
}
}
float matrix[nbLines * nbColumns];
You're creating a variable length array, and, of pointers.
While other answers are perfectly valid, if you really want a 2D array, you just need to change the declaration:
float matrix[nbLines][nbColumns];
to declare a 2D variable length array of floats.
Now the hard point is to pass this VLA to a function and preserve dimensions.
For that you could use C99 way of passing VLAs (note that dimensions must be located before the VLA itself). Reference: Passing a multidimensional variable length array to a function:
void enterMatrix(int nbLines, int nbColumns, float matrix[][nbColumns] ){
for (int i = 0; i < nbLines; i++){
for (int j = 0; j < nbColumns; j++)
{
scanf("%f", &matrix[i][j]);
}
}
}
call as follows:
enterMatrix(nbLines, nbColumns, matrix);

Error: subscripted value is not an array, pointer, or vector and idk what the issue is? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
The purpose of this exercise is to use the two-subscript method of dynamic memory allocation.
Input for this program is a two-dimensional array of floating point data located in a file named
testdata2. The input array will contain 3 rows of data with each row containing 5 columns of data.
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
int temp;
int number;
int r = 3;
int c = 5;
fp = fopen("testdata2.txt", "r");
number = (int)malloc(r * c * sizeof(int));
while (fscanf(fp, "%d", &temp) != EOF){
for(int i = 0; i < 3;i++){
for(int j = 0; j < 5; j++){
temp = number[i][j];
}
}
}
return(0);
}
Among the plethora of things incorrect in your code (any one of which can result in undefined behavior):
The core data type is wrong. The question specifically calls for floating-point values, yet you're using integer types.
The receiver of any memory allocation in C should be a pointer; you're using a simple int.
You're hiding whatever warnings/errors you're receiving by hard-casting. Casting malloc in C isn't necessary, nor advised.
Even if everything else were fixed, your assignment statement for temp = ... is backward. You want to save the value just-read into your matrix, not throw it away and overwrite it with whatever undefined value resides in your memory-just-allocated.
All of that said, knowing the width of your array of arrays is five, the problem reduces to this. Note temp isn't needed at all
#include <stdio.h>
#include <stdlib.h>
int main()
{
static const size_t r = 3;
static const size_t c = 5;
FILE *fp = NULL;
double (*number)[c] = NULL; // pointer to array of dimension c.
fp = fopen("testdata2.txt", "r");
if (fp == NULL)
{
perror("Failed to open file: ");
return EXIT_FAILURE;
}
number = malloc(r * sizeof *number); // allocate r-rows of dimension c
if (number == NULL)
{
perror("Failed to allocate array of arrays: ");
return EXIT_FAILURE;
}
for (size_t i=0; i<r; ++i)
{
for (size_t j=0; j<c; ++j)
{
if (fscanf(fp, "%lf", number[i]+j) != 1)
{
fprintf(stderr, "Failed to parse int at %zu,%zu", i, j);
return EXIT_FAILURE;
}
}
}
for (size_t i=0; i<r; ++i)
{
for (size_t j=0; j<c; ++j)
printf("%lf ", number[i][j]);
fputc('\n', stdout);
}
free(number);
return(0);
}
You are declaring an integer:
int number;
and you are allocating memory with malloc assuming it is a multi-dimensional array, then trying to access its elements in the same way.
Change the declaration to:
int **number;
it is not
(int)malloc(rcsizeof(int))
It is
(int*) malloc(rcsizeof(int))
One more mistake is that you can't access the elements as
temp=number[i][j];
Replace it with
temp=number[i*r+j]
Hope this helps
number = (int)malloc(r * c * sizeof(int));
In C, never cast the result of a malloc. If you had left out the cast to int, you'd have a diagnostic here telling you that number is not a pointer type.
You can do this:
int* number = malloc(r * c * sizeof(int));
But that gives you one big single dimensional array. You would need to dereference it like this:
temp = number[i * c + j];
If you want two dimensional indices as if you had declared it like this:
int number[r][c];
you need to allocate it in two stages:
int** number = malloc(r * sizeof(int*));
number[0] = malloc(r * c * sizeof(int));
for (int i = 1 ; i < r ; i++)
{
number[i] = &number[0][i * c];
}
That sets up a big array of ints and an intermediate array of pointers to ints for each row. Now you can do
temp = number[i][j];
Edit
Or you can do what Dmitri says which is this:
int (*number)[c] = malloc(r * c * sizeof(number[0][0]));
That effectively mallocs an array of r blocks of c ints in one go.

fread'ing a binary file into a dynamically allocated C array

Just a quick comment to start: While there are similar threads to this one, I haven't quite been able to find the solution I'm looking for. My problem is the following:
I have 2D arrays of doulbes saved to binary files and I would like to read the binary files (using C code) into a 2D array. Additionally, I need to allocate the memory dynamically as the shape of the arrays will be changing in my application. To get started, I tried the following code:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int main(){
int N = 10; //number of rows of 2D array
int M = 20; //number of columns
/* first allocate the array */
double **data;
data = (double **)malloc(N*sizeof(double *));
for(unsigned int i=0; i < N; i++) {
data[i] = (double *)malloc(sizeof(double)*M);
}
FILE *ptr;
ptr = fopen("random_real_matrix.dat", "rb");
fread(data, sizeof(data), 1, ptr);
for(unsigned int i=0; i<10;i++){
for(unsigned int j=0; j<20;j++){
fprintf(stderr, "m[%d][%d] = %f\n ", i, j, data[i][j]);
}
}
}
Unfortunately, this code segfaults. I checked to see if I can set the array entries like
d[0][0] = 235;
and that works fine.
Assuming this approach can be fixed, I'm also interested to know if it could be extended to read to an array of double complex's.
Any advice would be greatly appreciated!
Your fread statement is incorrect. It's a common beginner mistake to think that sizeof gets the size of a dynamically allocated array. It doesn't. In this case it just returns the size of a double **. You will need to read in each double in the file and put that into the correct spot in the array.
for (int ii = 0; ii < N; ++ii)
{
for (int jj = 0; jj < M; ++jj)
{
fread(data[ii][jj], sizeof(double), 1, ptr);
// Be sure to check status of fread
}
}
You can do this with a single for loop (or a single fread) but this is probably clearer to read.
Because you allocated each row separately, you can't read into the entire array at once. You need to do it row by row.
for (int i = 0; i < N; i++) {
fread(data[i], sizeof(double), M, ptr);
}

qsort in C based on a column in 2d array: unexpected behavior

I am trying to sort a 2d array based on a particular column using qsort in C. I am attaching a minimal working code I am using. Essentially I am passing the pointer to the rows of the array to qsort, and based on the column number I want to sort, I modify the element to compare inside the compare function. Now, according to C convention, if I have 2 columns, I expect colnum=0 and colnum=1 to correspond to columns 1 and 2. But, in my implementation, I get the correct result if colnum=1 means column 1 and colnum=2 means column 2. I am stumped as to why this should be ? (I have also included the array allocation function I use).
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "myfun.h"
static int colnum = 0;
int cmp(const void * a,const void * b);
int main(){
int i;
double **z1;
z1=matrix(5,2);
for (i=0; i<5; i++){
z1[i][1]=-i-1; z1[i][2]=16*i+10;
printf("before sort z1 %lf %lf \n",z1[i][1],z1[i][2]);
}
colnum=2;
qsort(z1,5,sizeof(double*),cmp);
for (i=0; i<5; i++){
printf("after sort z1 %lf %lf \n",z1[i][1],z1[i][2]);
}
getchar();
}
int cmp(const void * a,const void * b)
{
double** x = (double**) a;
double** y = (double**) b;
double xval, yval;
xval = *(*(x)+colnum);
yval = *(*(y)+colnum);
printf("%lf %lf \n",xval,yval);
if (xval < yval )
{
return 1;
}
else if (xval > yval)
{
return -1;
}
else
{
return 0;
}
}
double** matrix(int rows,int cols){
int k;
double **m;
m = (double **)malloc(rows * sizeof(double *));
for (k=0; k<rows; k++){
m[k] = (double *)malloc(cols * sizeof(double));
}
return m;
}
Your program has undefined behavior, because your are accessing memory beyond the boundary allocated by your inner allocation loop of matrix():
m = (double **) malloc(rows * sizeof(double *));
for (k = 0; k < rows; k++) {
m[k] = (double *) malloc(cols * sizeof(double));
}
Since cols has the value 2, malloc() only returns memory for 2 elements of type double. But, your code is initializing and reading a non-existing third element instead.
Since doing so is undefined, producing the output you expect is within the realm of possible behaviors. However, it is incorrect since you run the risk of corrupting the heap, and reading invalid data. Running your program under valgrind produces "Invalid write" and many "Invalid read" errors due to this problem in your program.
The correct approach is to store the values in their proper 0 and 1 column indexes in your initialization, set colnum to 1 to sort by the second column, and read from the proper 0 and 1 indexes when you print the array values.
z1 = matrix(5, 2);
for (i = 0; i < 5; i++) {
z1[i][0] = -i - 1;
z1[i][1] = 16 * i + 10;
printf("before sort z1 %lf %lf \n", z1[i][0], z1[i][1]);
}
colnum = 1;
qsort(z1, 5, sizeof(double *), cmp);
for (i = 0; i < 5; i++) {
printf("after sort z1 %lf %lf \n", z1[i][0], z1[i][1]);
}
As a side note, when I was formatting your code for this answer, I noticed that you used an old C anachronism, probably unintentionally:
z1[i][1]=-i-1; /*...*/
The =- construct was the original C's (pre C.89) way of spelling the -= operator. It is highly unlikely you will end up using a compiler that will honor that operator without a diagnostic, but you should be wary of this syntax, and separate the = and the - tokens to remove the ambiguity.
z1[i][1] = -i - 1; /*...*/

How to malloc a 2d jagged array using a pointer passed by reference to a function in C

I have a 2D jagged array declared in my main() block. This is to be passed to a function to have memory allocated to it. The following is the most reduced case which compiles but crashes when it runs. Where am I going wrong?
#include <stdio.h>
#include <stdlib.h>
void alloc2d(double ***p);
int main () {
double **data;
alloc2d(&data);
printf("Before assign to data\n");
data[0][0] = 0.1;
printf("After assign to data\n");
free(data);
}
void alloc2d(double ***p) {
int i, n, m;
// Get some dynamically assigned sizes
printf("Enter size: ");
scanf("%d %d", &n, &m);
// Now allocate
*p = malloc(n * sizeof(double*));
for (i = 0; i < n; i++) {
*p[i] = malloc(m * sizeof(double));
}
printf("End of alloc2d\n");
}
This reads the values but crashes when I enter low numbers (i.e. '1 1') but crashes when I enter high numbers (i.e. '10 10').
You made a very simple syntax error
*p[i] = (double*)malloc(m * sizeof(double));
should really be
(*p)[i] = (double*)malloc(m * sizeof(double));
This is because in C, [] operator has higher precedence than *.
So when you type *p[i],
it is translated into **(p + i).
This means: you are asking the compiler to calculate the address by offsetting the address of p by i * sizeof(double**), which is clearly not what you actually want.
So, in order to force the compiler to dereference p first, simply surroud *p with brackets.
Operator precedence is the answer. *p[i] is equivalent to *(p[i]). This makes you access memory that lies right after the data pointer, which will either corrupt some other variables on the stack, or crash completely.
You were looking for (*p)[i], which will be the i-th entry in the newly allocated array.
What your alloc2d() allocates is not really a 2D array, but:
1 1D n-long array of pointers to double
n 1D m-long arrays of doubles
Multi-dimensional arrays in C are only possible, if all but the last of the dimensions are known at compile-time:
double a[5][11];
Maybe, this program can help you understand... Note, how COLUMNS is a compile-time constant, even if rows is a run-time variable:
#include <stdio.h>
#include <stdlib.h>
#include <sysexits.h>
#include <err.h>
typedef double myrow_t[11]; /* 11 columns */
#define COLUMNS (sizeof(myrow_t)/sizeof(double))
static unsigned
alloc2d(myrow_t **pd)
{
unsigned int rows;
printf("Enter the number of rows: ");
while (scanf("%u", &rows) != 1)
printf("\ninvalid input, please, try again: ");
*pd = malloc(rows * sizeof(**pd));
if (*pd == NULL)
err(EX_TEMPFAIL, "Out of memory");
return rows;
}
int
main()
{
myrow_t *d;
unsigned int row, column, rows;
rows = alloc2d(&d);
for (row = 0; row < rows; row++)
for (column = 0; column < COLUMNS; column++)
d[row][column] = row * column;
for (row = 0; row < rows; row++) {
printf("Row %3d:\t", row);
for (column = 0; column < COLUMNS; column++)
printf("%.0f\t", d[row][column]);
puts("");
}
free(d);
return 0;
}

Resources