allocate 2d array in function and return it to caller

M

M. Moennigmann

Dear all:
I would like to write a function that opens a file, reads and stores
data into an 2d array, and passes that array back to the caller
(=main). The size of the array is not known before opening to the
file.

I fail to write a function that allocates memory for a 2d array and
returns it to main. I was trying to pass a pointer to the array back
to main, but main cannot access the data. The simplified code (no
opening of file, but only allocation) is attached below along with the
output.

I will appreciate any comment on what is going wrong. Thank you for
your help.
Martin

#include <stdlib.h>
#include <stdio.h>
int create2DimArray(int nx,
int ny,
double ***pointerToMyArray){
int i, j;
double **myArray;

// allocate memory for 2d array
myArray= (double **) malloc(nx* sizeof(double *));
for (i= 0; i< nx; i++){
myArray= (double *) malloc(ny* sizeof(double));
}

// fill array with funny numbers just for testing
for (i= 0; i< nx; i++){
for (j= 0; j< ny; j++){
myArray[j]= 1000.0* (double) i+ (double) j;
}
}

// print array to screen for testing/debugging
printf("in create2DimArray:\n");
for (i= 0; i< nx; i++){
for (j= 0; j< ny; j++){
printf(" i= %d, j= %d, %f\n", i, j, myArray[j]);
}
}

// return point er to array to caller
pointerToMyArray= &myArray;
return 0;
}

int main(){
int nx, ny, i, j;
double ***pointerToMyArray;
double **myArray;

nx= 3;
ny= 4;

// create 2d array
create2DimArray(nx, ny, pointerToMyArray);
myArray= *pointerToMyArray;

// try to print array to screen
printf("in main:\n");
for (i= 0; i< nx; i++){
for (j= 0; j< ny; j++){
printf(" i= %d, j= %d, %f\n", i, j, myArray[j]);
}
}

return 0;
}

-----------------------------------------

output

-----------------------------------------
in create2DimArray:
i= 0, j= 0, 0.000000
i= 0, j= 1, 1.000000
i= 0, j= 2, 2.000000
i= 0, j= 3, 3.000000
i= 1, j= 0, 1000.000000
i= 1, j= 1, 1001.000000
i= 1, j= 2, 1002.000000
i= 1, j= 3, 1003.000000
i= 2, j= 0, 2000.000000
i= 2, j= 1, 2001.000000
i= 2, j= 2, 2002.000000
i= 2, j= 3, 2003.000000
in main:
Segmentation fault
 
D

Darrell Grainger

Dear all:
I would like to write a function that opens a file, reads and stores
data into an 2d array, and passes that array back to the caller
(=main). The size of the array is not known before opening to the
file.

When it is known? If the file has the information as a header it makes it
easier. If the file just have raw data and you have to determine the size
at run time it would be more difficult.
I fail to write a function that allocates memory for a 2d array and
returns it to main. I was trying to pass a pointer to the array back
to main, but main cannot access the data. The simplified code (no
opening of file, but only allocation) is attached below along with the
output.

I will appreciate any comment on what is going wrong. Thank you for
your help.

Here is one way to do it...

double **array;
allocate ROW * sizeof (double*), one pointer for each row of data
for each pointer
allocate COLUMN * sizeof double
return array

Even better would be, rather than the for each pointer code, allocate one
large block of memory (ROW*COLUMN*sizeof double) then have a for loop that
assigns a section of the memory to each pointer. This is better because
you only have two calls to malloc rather than ROW+1.
Martin

#include <stdlib.h>
#include <stdio.h>
int create2DimArray(int nx,
int ny,
double ***pointerToMyArray){
int i, j;
double **myArray;

// allocate memory for 2d array
myArray= (double **) malloc(nx* sizeof(double *));

There is no need for the (double**) cast. It actually can hide mistakes.
If you forget to #include <stdlib.h> this could be a serious mistake.
Otherwise, this code corresponds to my allocating the ROW pointers.

By the way, what happens if malloc fails? Shouldn't you be checking for
this possibility and handling it. Both here and in all the calls below.
for (i= 0; i< nx; i++){
myArray= (double *) malloc(ny* sizeof(double));
}


Again, lose the cast and check the results of th e malloc. This code is
more like the less efficient first method I presented.
// fill array with funny numbers just for testing
for (i= 0; i< nx; i++){
for (j= 0; j< ny; j++){
myArray[j]= 1000.0* (double) i+ (double) j;
}
}

// print array to screen for testing/debugging
printf("in create2DimArray:\n");
for (i= 0; i< nx; i++){
for (j= 0; j< ny; j++){
printf(" i= %d, j= %d, %f\n", i, j, myArray[j]);
}
}

// return point er to array to caller
pointerToMyArray= &myArray;


Not quite. Try:

*pointerToMyArray = myArray;
return 0;
}

int main(){
int nx, ny, i, j;
double ***pointerToMyArray;

Nope. Try:

double **pointerToMyArray;
double **myArray;

nx= 3;
ny= 4;

// create 2d array
create2DimArray(nx, ny, pointerToMyArray);

create2DimArray(nx, ny, &pointerToMyArray);
myArray= *pointerToMyArray;

// try to print array to screen
printf("in main:\n");
for (i= 0; i< nx; i++){
for (j= 0; j< ny; j++){
printf(" i= %d, j= %d, %f\n", i, j, myArray[j]);
}
}

return 0;
}

-----------------------------------------

output

-----------------------------------------
in create2DimArray:
i= 0, j= 0, 0.000000
i= 0, j= 1, 1.000000
i= 0, j= 2, 2.000000
i= 0, j= 3, 3.000000
i= 1, j= 0, 1000.000000
i= 1, j= 1, 1001.000000
i= 1, j= 2, 1002.000000
i= 1, j= 3, 1003.000000
i= 2, j= 0, 2000.000000
i= 2, j= 1, 2001.000000
i= 2, j= 2, 2002.000000
i= 2, j= 3, 2003.000000
in main:
Segmentation fault
 
E

Emmanuel Delahaye

In said:
I would like to write a function that opens a file, reads and stores
data into an 2d array, and passes that array back to the caller
(=main). The size of the array is not known before opening to the
file.

You can't 'pass (or return) an array' in C (And if you could, it would be
silly). You only can pass it's address and probaly interesting information
like its dimensions.

You probably need some structure to gather these information. A generic
dynamic 2D array could be :

typedef struct
{
/* array address */
void *a;

/* element size */
size_t es;

/* number of colomns */
size_t col;

/* number of lines */
size_t lin;
}
two_dim_s;
I fail to write a function that allocates memory for a 2d array and
returns it to main.

On this basis, it's now quite simple :

#include <stdlib.h>

two_dim_s *two_dim_create (size_t es, size_t col, size_t lin)
{
/* allocates the object */
two_dim_s *this = malloc (sizeof *this);

if (this != NULL)
{
/* let's clear the object properly */
{
static two_dim_s z = {0};
*this = z;
}

/* allocates a linear array */
this->a = malloc (es * col * lin);

if (this->a != NULL)
{
/* stores the size information */
this->es = es;
this->col = col;
this->lin = lin;
}
else
{
/* memory error : delete the object and return NULL */
two_dim_delete (this);
this = NULL;
}
}

return this;
}

we also need the delete function :

void two_dim_delete (two_dim_s *this)
{
if (this != NULL)
{
/* free the array */
free (this->a);

/* debug purpose (and good manner too) */
this->a = NULL;

/* free the object */
free (this)
}
/* debug purpose (and good manner too) */
this= NULL;
}

Now, we need accessors. I give you the interfaces of the functions, but I let
you write the bodies.
The returned int is the error condition :
- 0 = OK
- <>0 = Error. Values to be defined.

int two_dim_write (two_dim_s *this, void const *p_value, size_t x, size_t y)
{
/* fill-in */
}

int two_dim_read (two_dim_s *this, void *p_value, size_t x, size_t y)
{
/* fill-in */
}

You'll need an 'internal' function that computes the address of an element
from its position. It's actually the 'heart' of the object :

static void *get_adddr (two_dim_s *this, size_t x, size_t y)
{
}

Important notice : None of the above code has been compiled or tested. It's
just a guideline.
 
B

Barry Schwarz

Dear all:
I would like to write a function that opens a file, reads and stores
data into an 2d array, and passes that array back to the caller
(=main). The size of the array is not known before opening to the
file.

I fail to write a function that allocates memory for a 2d array and
returns it to main. I was trying to pass a pointer to the array back
to main, but main cannot access the data. The simplified code (no
opening of file, but only allocation) is attached below along with the
output.

I will appreciate any comment on what is going wrong. Thank you for
your help.
Martin

#include <stdlib.h>
#include <stdio.h>
int create2DimArray(int nx,
int ny,
double ***pointerToMyArray){

It would be much easier all around if the function returned the
address of the 2d array (or NULL in case of failure) rather than the
constant 0 and the use of the apparently confusing double***.
int i, j;
double **myArray;

// allocate memory for 2d array
myArray= (double **) malloc(nx* sizeof(double *));

Don't cast the return from malloc. All you accomplish is suppressing
the diagnostic that would warn you about invoking undefined behavior
if you forget to include stdlib.h.

Always check the return from malloc for success before using it.
for (i= 0; i< nx; i++){
myArray= (double *) malloc(ny* sizeof(double));
}

// fill array with funny numbers just for testing
for (i= 0; i< nx; i++){
for (j= 0; j< ny; j++){
myArray[j]= 1000.0* (double) i+ (double) j;


Both casts are unnecessary.
}
}

// print array to screen for testing/debugging
printf("in create2DimArray:\n");
for (i= 0; i< nx; i++){
for (j= 0; j< ny; j++){
printf(" i= %d, j= %d, %f\n", i, j, myArray[j]);
}
}

// return point er to array to caller
pointerToMyArray= &myArray;


myArray is an automatic variable which will go out of existence as
soon as this function returns. Therefore, attempting to use its
address after that time would invoke undefined behavior.

pointerToMyArray is a parameter of the function and will also
disappear at the end of the function. Assigning a value to it can
never have any affect on the calling function.

What you want here is
*pointerToMyArray = myArray;
return 0;

Why bother? It doesn't tell the calling function anything.
}

int main(){
int nx, ny, i, j;
double ***pointerToMyArray;
double **myArray;

nx= 3;
ny= 4;

// create 2d array
create2DimArray(nx, ny, pointerToMyArray);
myArray= *pointerToMyArray;

As noted above, you did not change main's copy of pointerToMyArray.
If you had, this attempt to dereference would invoke undefined
behavior.

You want to replace these two lines with
create2DimArray(nx, ny, &myArray);

Coupled with the change above, it will cause the function to store the
address IN function's myArray (not the address OF function's myArray)
in main's myArray so that main can then refer to the doubles using
normal subscript notation.
// try to print array to screen
printf("in main:\n");
for (i= 0; i< nx; i++){
for (j= 0; j< ny; j++){
printf(" i= %d, j= %d, %f\n", i, j, myArray[j]);
}
}


For completeness, you should free all the allocated memory.
return 0;
}

-----------------------------------------

output

-----------------------------------------
in create2DimArray:
i= 0, j= 0, 0.000000
i= 0, j= 1, 1.000000
i= 0, j= 2, 2.000000
i= 0, j= 3, 3.000000
i= 1, j= 0, 1000.000000
i= 1, j= 1, 1001.000000
i= 1, j= 2, 1002.000000
i= 1, j= 3, 1003.000000
i= 2, j= 0, 2000.000000
i= 2, j= 1, 2001.000000
i= 2, j= 2, 2002.000000
i= 2, j= 3, 2003.000000
in main:
Segmentation fault



<<Remove the del for email>>
 
E

E. Robert Tisdale

M. Moennigmann said:
I would like to write a function that opens a file, reads and stores
data into an 2d array, and passes that array back to the caller
(=main). The size of the array is not known before opening to the
file.

I fail to write a function that allocates memory for a 2d array and
returns it to main. I was trying to pass a pointer to the array back
to main, but main cannot access the data. The simplified code (no
opening of file, but only allocation) is attached below along with the
output.

I will appreciate any comment on what is going wrong.
Thank you for your help.


> cat main.c
#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char* argv[]) {
int result = EXIT_SUCCESS;
if (1 < argc) {
FILE* fp = fopen(argv[1], "r");
if (NULL != fp) {
size_t m, n;
if (2 == fscanf(fp, "%u%u", &m, &n)) {
double A[m][n];
for (size_t i = 0; i < m; ++i)
for (size_t j = 0; j < n; ++j)
fscanf(fp, "%lf", &(A[j]));
fprintf(stdout, "A =\n");
for (size_t i = 0; i < m; ++i) {
for (size_t j = 0; j < n; ++j)
fprintf(stdout, " %f", A[j]);
fprintf(stdout, "\n");
}
}
else { // (2 != fscanf(fp, "%u%u", &m, &n))
fprintf(stderr, "Failed to read array dimensions!\n");
result = EXIT_FAILURE;
}
fclose(fp);
}
else { // (NULL == fp)
fprintf(stderr, "Failed to open file: %s\n", argv[1]);
result = EXIT_FAILURE;
}
}
else { // (argc <= 1)
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
result = EXIT_FAILURE;
}
return result;
}
> gcc -Wall -std=c99 -pedantic -o main main.c
> cat data
2 5
0 1 2 3 4
5 6 7 8 9
> ./main data
A =
0.000000 1.000000 2.000000 3.000000 4.000000
5.000000 6.000000 7.000000 8.000000 9.000000
 
B

Barry Schwarz

cat main.c
#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char* argv[]) {
int result = EXIT_SUCCESS;
if (1 < argc) {
FILE* fp = fopen(argv[1], "r");
if (NULL != fp) {
size_t m, n;
if (2 == fscanf(fp, "%u%u", &m, &n)) {

m and n are not unsigned. You should be using %d.
double A[m][n];

This will only work for a C99 compiler.
for (size_t i = 0; i < m; ++i)

The declaration of i inside the for statement is a non-standard
extension.
for (size_t j = 0; j < n; ++j)
fscanf(fp, "%lf", &(A[j]));
fprintf(stdout, "A =\n");
for (size_t i = 0; i < m; ++i) {
for (size_t j = 0; j < n; ++j)
fprintf(stdout, " %f", A[j]);
fprintf(stdout, "\n");
}
}
else { // (2 != fscanf(fp, "%u%u", &m, &n))


// comments are a C99 addition.
fprintf(stderr, "Failed to read array dimensions!\n");
result = EXIT_FAILURE;
}
fclose(fp);
}
else { // (NULL == fp)
fprintf(stderr, "Failed to open file: %s\n", argv[1]);
result = EXIT_FAILURE;
}
}
else { // (argc <= 1)
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);

The angle brackets usually denote optional parameters. filename is
not optional.
result = EXIT_FAILURE;
}
return result;
}

2 5
0 1 2 3 4
5 6 7 8 9

A =
0.000000 1.000000 2.000000 3.000000 4.000000
5.000000 6.000000 7.000000 8.000000 9.000000



<<Remove the del for email>>
 
V

Vittal

Slight modification to your code solves the problem..

#include <stdlib.h>
#include <stdio.h>
int create2DimArray(int nx,
int ny,
++++++++++++++++++++++++++++
double ****pointerToMyArray){
++++++++++++++++++++++++++++++
int i, j;
double **myArray;

// allocate memory for 2d array
myArray= (double **) malloc(nx* sizeof(double *));
for (i= 0; i< nx; i++){
myArray= (double *) malloc(ny* sizeof(double));
}

// fill array with funny numbers just for testing
for (i= 0; i< nx; i++){
for (j= 0; j< ny; j++){
myArray[j]= 1000.0* (double) i+ (double) j;
}
}

// print array to screen for testing/debugging
printf("in create2DimArray:\n");
for (i= 0; i< nx; i++){
for (j= 0; j< ny; j++){
printf(" i= %d, j= %d, %f\n", i, j, myArray[j]);
}
}

// return point er to array to caller

++++++++++++++++++++++++++++++
*pointerToMyArray= &myArray;
+++++++++++++++++++++++++++++++
return 0;
}

int main(){
int nx, ny, i, j;
double ***pointerToMyArray;
double **myArray;

nx= 3;
ny= 4;

// create 2d array
create2DimArray(nx, ny, pointerToMyArray);
myArray= *pointerToMyArray;

// try to print array to screen
printf("in main:\n");
for (i= 0; i< nx; i++){
for (j= 0; j< ny; j++){
printf(" i= %d, j= %d, %f\n", i, j, myArray[j]);
}
}

return 0;
}
 
D

Dave Thompson

On Tue, 01 Jun 2004 12:52:32 -0700, "E. Robert Tisdale"
double A[m][n];

This will only work for a C99 compiler.
Or gcc even before '99 as an extension.
The declaration of i inside the for statement is a non-standard
extension.
Standard in C99, nonstandard before that.

// comments are a C99 addition.
Yes. Plus unwise in news, not that ERTroll is a paragon of netiquette.
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);

The angle brackets usually denote optional parameters. filename is
not optional.
*Square* brackets [] often indicate optional, although they are also
used for other things, like character classes. Angle brackets indicate
nonterminals in (some notations of) BNF; also HTML (and XML) tags,
often mandatory or at least necessary; and C++ template parameters, at
least some mandatory; and RFC822+ addresses and message-ids, and
RFC-I-forget delimited URLs, which are not at all optional; and the
same characters are used for I/O redirection in Unix and now other
(CUI) systems. (Angle and square brackets were also used for
directories in older DEC OSes, and the former for pathnames in Multics
and Stratus^WIBM VOS, but those aren't so relevant now.)

In theory argv[0] can be NULL, in which case this is undefined
behavior; or empty if the implementation can't provide it, in which
case the display is misleading, although in that circumstance there
isn't anything really much better we can do.

- David.Thompson1 at worldnet.att.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,983
Messages
2,570,187
Members
46,747
Latest member
jojoBizaroo

Latest Threads

Top