I read on some ways to dynamically create and use a 2D array, and I've settled on this way:
file:
5 4
+---+
|xxx|
|xxx|
+---+
main.c:
char** loadArray() {
FILE *in = fopen("file", "r");
int w, h;
fscanf(in, "%d %d\n", &w &h);
char (*buf)[w] = malloc(sizeof(char[h][w]));
for (int i = 0; i < h; i++) {
fscanf(in, "%s\n", buf[i]);
}
fclose();
return buf;
}
int main() {
char** array = loadArray();
for (int i = 0; i < 4; i++) { // magic number, only because I know the size
printf("%s\n", array[i]);
}
return 0;
}
While this does compile, it gives a warning: incompatible pointer types returning 'char (*)[w]' from a function with result type 'char **', and segfaults if I try to run it.
Several questions (mainly for C, but C++ specific answers are welcome for future reference, when I get there):
What is the correct return type for a multidimensional array? The warning isn't quite helpful I think, since it offers a variable term, which I obviously don't have until I read the file.
At this point, I'm just trying to get returning 2D arrays to work, but when I do and move on, I'm going to need the dimensions of the array for proper usage later on. My first idea would be to return structs instead, where I can save the dimension and the array itself. However, after further thought, the variable size makes me think that I wouldn't be able to have a single struct template to use as the function's return type, and I would have to find some other way to get the size along with the array. Are ideas?
Thank you for your time.
Pointer to pointer and pointer to array are quite different things. You can't return the array dimension as such in the return type so you'd have to use an incomplete array:
char (*(loadArray()))[] {
...
}
Evidently this is not very readable so you'd better pass through a typedef:
typedef char line[];
line* loadArray() {
...
}
You'd also have to get your hands on the dimensions w and h, so you'd have to pass pointers to the values as arguments. But that would be another question.
What is the correct return type for a multidimensional array?
There is no "correct" type, it all depends on how you want to represent the data and what architecture you want to design.
The warning isn't quite helpful I think, since it offers a variable term
The warning is very helpful, because it indicates an error in the code - you are casting a pointer to an array to a pointer to a pointer. Ignoring that warning ultimately leads to printf("%s\n", array[i]); which is undefined behavior.
Are ideas?
You may return a pointer to a dynamically allocated array of pointers to dynamically allocated array of values.
char **loadArray(void) {
size_t w, h;
// Initialize w and h.
char **arr;
arr = malloc(w * sizeof(*arr));
if (!arr) return NULL;
for (size_t i = 0; i < w; ++i) {
arr[i] = malloc(h * sizeof(*arr[i]));
if (!arr[i]) {
for (size_t j = 0; j < i; ++j) {
free(arr[j]);
}
frer(arr);
return NULL;
}
}
// Fill arr from file. Handle errors. Handle deallocation.
return arr;
}
which is the usual way to program in C and one would expect char ** to act that way. I can thing of an example from POSIX , where scandir function takes a pointer to a double pointer struct dirent ***namelist argument which is assigned to a such dynamically allocated 2d array.
But let's take a bit over-engineered (or not) design (in mostly C-ish pseudocode):
// represents the thing
struct thething_s {
char *string;
};
int thething_print(struct thething_s *t, FILE *f) {
return fprintf(f, ....);
}
void thething_free(struct thething_s *t) {
free(t->string);
}
int thething_load_from_file(struct thething_s *t, FILE *f, size_t len) {
t->string = malloc(len);
if (!t->string) return -1;
if (scanf(....) != 1) return -2;
return 0;
}
// represents an array of things
struct thingsarr_s {
struct thethings_s *things;
size_t w;
size_t h;
};
int thigsarr_load_from_file(struct thingsarr_s *t, FILE *f) {
// Initialize t->w and t->h.
t->things = malloc(t->w * sizeof(*t->things));
if (!arr) return -1;
for (size_t i = 0; i < w; ++i) {
if (thething_load_from_file(&t->things[i], f, t->h) != 0) {
for (size_t j = 0; j < i; ++j) {
thethings_free(t->things[j]);
}
free(t->things);
return -1000 - i;
}
}
return 0;
}
const struct thething_s *thingsarr_get_thing(const struct thingsarr_s *t, size_t idx)
{
assert(idx < t->len);
return t->things[idx];
}
struct thething_s *thingsarr_get_thing_nonconst(struct thingsarr_s *t, size_t idx) {
return (struct thething_s *)thingsarr_get_thing(t, idx);
}
void thingsarr_free(struct thingsarr_s *t) {
for (.,.) {
thething_free(&t->things[i]);
}
free(t->things);
}
Which is "best" strongly depends on the context, specific needs and specific application.
The pointer types char ** and char (*)[w] are very different. There is a common misconception that arrays and pointers are the same thing in C, but that is not the case.
You want the return type of the function to be char (*)[w], but that return type is impossible to declare because w is an unknown value. Also, the caller doesn't know the width and height of the returned array, because that information is internal to the loadArray function.
Setting the return type of the loadArray function to void* allows it to just return a pointer to the array without knowing the width or height. The width and height values can be sent to the caller using pointer arguments so that the caller can reconstruct the array type.
The following modifications of the original C code implements the above change. (C++ does not support variable length array types as far as I know, so this is C only.)
#include <stdio.h>
#include <stdlib.h>
void* loadArray(int *pw, int *ph) {
FILE *in = fopen("file", "r");
int w, h;
fscanf(in, "%d %d\n", &w, &h);
*pw = w;
*ph = h;
char (*buf)[w] = malloc(sizeof(char[h][w]));
for (int i = 0; i < h; i++) {
fscanf(in, "%s\n", buf[i]);
}
fclose(in);
return buf;
}
int main(void) {
int w, h;
void* larray = loadArray(&w, &h);
char(*array)[w] = larray;
for (int i = 0; i < h; i++) {
printf("%s\n", array[i]);
}
return 0;
}
Related
so I am loading lines of floats from text files and storing them in a pointer array, before saving them back to a text file and adding a reference to their size. The number of values in the text file varies so the array must be dynamic. I define my pointer array in main like this.
size_t size = (int)100 * sizeof(float);
float * val = malloc(size);
I then pass the pointer array to a function that loads the text file and saves the values to it, like this.
//Read file into array.
int readFile(float *val, int size) {
char buf[20] = { 0 };
val[0] = 0;
double temp = 0;
int i = 1;
FILE *file;
file = fopen("C:\\Users\\MoldOffice\\Dropbox\\VS\\finalproj\\ecgproject\\dataStream", "r");
if (!file) {
printf("Coulding find file.\n");
exit(1);
}
while (fgets(buf, 20, file) != NULL) {
temp = atof(buf);
if (temp != 0) {
// Increment i to find the size of the useful data.
val[i] = temp;
//printf("%d",val[i]);
i++;
if (i == size / sizeof(float)) {
size += 100*sizeof(float);
double* val_temp = realloc(val, size);
if (val_temp == NULL) {
printf("Realloc failed.\n");
}
else {
val = val_temp;
}
}
}
}
//Test that the array is readable.
for (int i = 0; i < 5; i++) printf("val[%d]=%f\n", i, val[i]);
return(i);
fclose(file);
This works fine and when I print the contents of the pointer array back in main, it works. I then pass the same pointer array to another function which saves the array in a new text file, along with the size on the first line, the problem is that when I pass the pointer array for a second time, the contents have changed (mostly 0 with some random numbers). I have absolutely no idea why this is happening.. Any ideas? The function that writes the file is here:
// Write file into array.
void writeFile(float *val,int size) {
printf("%d",sizeof(val));
FILE *file;
int sampleNum;
char buf[10];
file = fopen("sampleNum.txt", "r");
if (file == NULL) { sampleNum = 0; }
else { fscanf(file, "%d", &sampleNum); printf("%d",sampleNum);}
char fileString[10];
sprintf(fileString,"sample%d\0", sampleNum);
file = fopen(fileString, "w");
//Test that the array is readable.
for (int i = 0; i < 5; i++) printf("val[%d]=%f\n", i, val[i]);
//Print the array to a text file and save.
fprintf(file, "%d\n", size);
for (int i = 1; i < size; i++) {
fprintf(file, "%f\n", val[i]);
printf("%f\n", val[i]); }
fclose(file);
}
The rest of main can be found here:
int main() {
size_t size = (int)100 * sizeof(float);
float * val = malloc(size);
// Read the data into an array.
int arraySize = readFile(val, size);
//Test that the array is readable.
for (int i = 0; i < 5; i++) printf("val[%d]=%f\n", i, val[i]);
// Save the array to a text file, with the size of the array as the first element.
writeFile(val,arraySize);
}
double* val_temp = realloc(val, size);
if (val_temp == NULL) {
printf("Realloc failed.\n");
}
else {
val = val_temp;
The caller of this function has no way to know that you've moved the array to a different place. It's still got the old, now invalid, pointer.
You have a similar problem with size. How does the caller know you changed it?
You choice of division of responsibilities is poor. If the caller is responsible for allocating the buffer, then this function should ask the caller to enlarge it. If this function is responsible for allocating the buffer, it should allocate it. It's generally a very bad idea to split up the responsibility for managing the allocation of a chunk of memory, and this shows one of the reasons why.
Perhaps pass in a pointer to a structure that contains a pointer to a buffer and its size? That will work, but still shows poor division of responsibilities.
Perhaps have this function allocate the buffer and return a structure that includes a pointer to it and the number of elements in it?
If you really want to to do things this way, consider passing the function a pointer to a structure that includes a pointer to the array, the size of the array, and a pointer to a function that resizes the array. The caller can, of course, set this pointer to point to the realloc function (though it's probably better for it to be a function that changes the pointer and size members of the structure).
You could also use code like this:
struct float_buffer
{
float* buffer;
int size;
};
struct float_buffer allocate_float_buffer(int size)
{
struct float_buffer buf;
buf.buffer = malloc (size * sizeof(float));
buf.size = size;
return buf;
}
bool resize_float_buffer(struct float_buffer* buf, int size)
{
float* tmp = realloc(buf->buffer, size * sizeof(float));
if (tmp == NULL)
return false;
buf->buffer = tmp;
buf->size = size;
return true;
}
And then pass the function a struct float_buffer *.
I'm trying to refactor my code to make it better/more readable so I'm trying change a 2-D variable array allocation as follows
// OLD CODE
int **map;
map = calloc(number, sizeof(int *));
if (!(map)) {
free(map);
return 1;
}
for (int i = 0; i < number; i++) {
map[i] = calloc(number, sizeof(int));
if (!(map[i])) {
while (--i >= 0) {
free(map[i]);
}
free(map);
return 1;
}
}
// NEW CODE
int (*map)[number] = malloc(sizeof (int[number][number]));
if (!(map)){
free(map);
return 1;
}
The problem is that all my functions that use map take int **map and by changing the declaration of map like i did the IDE tells me incorrect type int[]* instead of int**
What should i use instead of int**? Using int[]* map in the function declaration tells me can't resolve variable map
Turns out the below code is not a C99 alternative #M.M, but a GCC extension.
Undocumented GCC Extension: VLA in struct
As a C99 GCC extension alternative to int (*map)[number] = malloc(sizeof (int[number][number])); for code simplification and maintain compatibility with existing function set, allocate all the memory needed with 1 *alloc() call.
This does require that when code is done with the map, all the memory is free'd with one free(map). Further, individual rows of map[] can no longer be re-allocated, but can be swapped within the map[].
int **map_allocate(size_t row, size_t column) {
struct {
int *ip[row]; // Array of pointers, followed by a ...
int i[row][column]; // 2D array of int
} *u;
u = calloc(1, sizeof *u);
if (u == NULL) {
return NULL;
}
for (size_t i = 0; i<row; i++) {
u->ip[i] = u->i[row];
}
return &u->ip[0];
}
Note: no casting and field i[][] is properly aligned.
To use one allocation with standard code, unlike the other answer, is a bit trickier as one needs to insure that a combined memory allocation of pointers and int needs to meet alignment concerns in the unusual case of int alignment requirements exceed pointer alignment ones. This is more easily shown with long long as below.
If this makes "code easier to read" is left to OP's judgment.
#include <stdlib.h>
#include <stdio.h>
long long **map_allocate_ll(size_t row, size_t column) {
long long **map;
long long *ints;
size_t pointers_sz = sizeof *map * row;
// extend pointer size to `*ints` boundary
pointers_sz = (pointers_sz + sizeof *ints - 1)/sizeof *ints * sizeof *ints;
size_t ints_sz = sizeof *ints * row * column;
printf("psize %zu, isize %zu\n", pointers_sz, ints_sz);
map = calloc(1, pointers_sz + ints_sz);
if (map == NULL) {
return NULL;
}
ints = (void*) ((char*) map + pointers_sz);
printf("map %p\n", (void *) map);
for (size_t i = 0; i<row; i++) {
map[i] = &ints[i * column];
printf("map[%zu] %p\n", i, (void *) map[i]);
}
return map;
}
int main() {
free(map_allocate_ll(5,3));
}
Sample output
psize 24, isize 120
map 0x80081868
map[0] 0x80081880
map[1] 0x80081898
map[2] 0x800818b0
map[3] 0x800818c8
map[4] 0x800818e0
I'm currently doing a C programme which requires the use of pointers, which I'm not great at.
I'm currently getting 4 errors which all say 'dereferencing pointer to incomplete type' and I don't know why.
Here is an example of how I set up my pointers and where I get the errors.
struct myset
{
unsigned char *vector;
int size;
int size_in_bytes;
int size_in_bits;
};
struct myset* set_new(int size)
{
int i;
struct myset* s;
s= malloc (sizeof (struct myset));
s->vector=malloc(sizeof(char)*(size/(sizeof(char)*8))+1);
for(i=0; i<size; i++)
{
s->vector[i]=0;
}
s->size_in_bits=size;
s->size_in_bytes=(size/(sizeof(char)))+1;
return s;
};
and I get an error whenever I try to reference the pointer, for example in this function.
void bitset_intersect(struct bitset * dest, struct bitset * src1, struct bitset * src2)
{
int maxSize = dest -> size_in_bits;
int i;
int j;
for(i = 0; i<maxSize; i++)
{
for(j = 0; j<maxSize; j++)
{
if(bitset_lookup(src1, i) == bitset_lookup(src2, j))
{
bitset_add(dest,i);
}
}
}
}
The error is in the line int maxSize = dest -> size_in_bits;
Any help would be appreciated, thanks.
Without the function call, its slightly hard to tell if you are passing the right values as parameters.
If you are getting an error while trying to reference the pointer, then check the function call to make sure you are passing the address correctly. Doing so would remove this error.
Both *dest and *src should have address that is being passed into it since both are from the same struct bitset.
I've tried to search out a solution via Google: I couldn't find anything that helped; it even seemed as if I was doing this correctly. The only pages I could find regarding sending my dynamically allocated array through a function dealt with the array being inside a struct, which is scalar of course, so behaves differently. I don't want to use a struct right now -- I'm trying to learn about DAM and working with pointers and functions.
That said, I'm sure it's very elementary, but I'm stuck. The code compiles, but it freezes up when I run the executable. (I'm using minGW gcc, if that matters. And I'm not clear at all, right now, on how to use gdb.)
Here's the code (eventually, I want the entire code to be an ArrayList-like data structure):
#include <stdio.h>
#include <stdlib.h>
void add( int element, int *vector);
void display_vector( int *vector );
void initialize_vector( int *vector );
int elements = 0;
int size = 10;
int main(void)
{
int *vector = 0;
initialize_vector(vector);
add(1, vector);
//add(2, vector);
//add(3, vector);
//add(4, vector);
//add(5, vector);
//add(6, vector);
//add(7, vector);
//add(8, vector);
//add(9, vector);
//add(10, vector);
//add(11, vector);
display_vector(vector);
return 0;
}
void add( int element, int *vector)
{
vector[elements++] = element;
return;
}
void display_vector( int *vector )
{
int i;
for( i = 0; i < elements; i++)
{
printf("%2d\t", vector[i]);
if( (i + 1) % 5 == 0 )
printf("\n");
}
printf("\n");
return;
}
void initialize_vector( int *vector )
{
vector = (int *)malloc(sizeof(int) * size);
}
Edited to make a little bit more clear.
The problem is your init routine is working with a copy of "vector" and is malloc'ing into that copy rather than the original vector pointer. You loose the pointer to the memory block on the return from the initialize.
Change parameter for vector to a handle (pointer to pointer) in this function
void initialize_vector( int **vector )
{
*vector = (int *)malloc(sizeof(int) * size);
}
Then change the call to init to this
initialize_vector(&vector);
I didn't compile this, but it should fix the code.
In C, function arguments are passed by value, which means there is a local copy for every arguments you passed to a function, if you change an argument in a function, you only change the local copy of that argument. So if you want to change the value of an argument in a function, you need to pass its address to that function, derefer that address and assign to the result in that function.
Enough for the theory, here is how to fix your code:
void initialize_vector( int **vector );
initialize_vector(&vector);
void initialize_vector( int **vector )
{
*vector = (int *)malloc(sizeof(int) * size);
}
In addition of other replies, I would suggest another approach.
Assuming at least C99 compliant compiler, I would rather suggest to keep the allocated size in a member of a structure ending with a flexible array member (see also this) like:
typedef struct vector_st {
unsigned count; // used length
unsigned size; // allocated size, always >= length
int vectarr[];
} Vector;
Then you would construct such a vector with
Vector* make_vector (unsigned size) {
Vector* v = malloc(sizeof(Vector)+size*sizeof(int));
if (!v) { perror("malloc vector"); exit (EXIT_FAILURE); };
memset (v->vectarr, 0, size*sizeof(int));
v->count = 0;
v->size = size;
}
To add an element into a vector, returning the original vector or a grown one:
Vector* append_vector (Vector*vec, int elem) {
assert (vec != NULL);
unsigned oldcount = vec->count;
if (oldcount < vec->size) {
vec->vectarr[vec->count++] = elem;
return vec;
} else {
unsigned newsize = ((4*oldcount/3)|7) + 1;
Vector* oldvec = vec;
vec = malloc(sizeof(Vector)+newsize*sizeof(int));
if (!vec) { perror("vector grow"); exit(EXIT_FAILURE); };
memcpy (vec->vectarr, oldvec->vectarr, oldcount*sizeof(int));
memset (vec->vectarr + oldcount, 0,
(newsize-oldcount) * sizeof(int));
vec->vectarr[oldcount] = elem;
vec->count = oldcount+1;
vec->size = newsize;
free (oldvec);
return vec;
}
}
and you could code:
Vector* myvec = make_vector(100);
myvec = append_vector(myvec, 35);
myvec = append_vector(myvec, 17);
for (int i=0; i<150; i++)
myvec = append_vector(myvec, i*2);
To release such a vector, just use free(myvec);
If you really don't want to use any struct you should keep in separate variables the used length of your vector, the allocated size of your vector, the pointer to your dynamically allocated array:
unsigned used_count; // useful "length"
unsigned allocated_size; // allocated size, always not less than used_count
int *dynamic_array; // the pointer to the dynamically allocated array
If you want to be able to manage several vectors, then either pack together the above useful length, allocated size and dynamic array into some struct dynamic_array_st (whose pointer you would pass to appropriate routines like make_dynamic_vector(struct dynamic_array_st*), append_dynamic_vector(struct dynamic_array_st*, int), etc ....) or else pass them as three separate formals to similar routines, and then you'll need to pass their address because the routines would change them, e.g. create_dynamic_vector(unsigned *countptr, unsigned *sizeptr, int**vectarrptr) that you would invoke as create_dynamic_vector(&mycount, &mysize, &myvectarr); etc.
I do think that a flexible array member is still the cleanest approach.
I messed around with this enough but I really don't get it.
Here is what I want to do: Take a 2D char array as an input in a function, change the values in it and then return another 2D char array.
That's it. Quite simple idea, but ideas do not get to work easily in C.
Any idea to get me started in its simplest form is appreciated. Thanks.
C will not return an array from a function.
You can do several things that might be close enough:
You can package your array in struct and return that. C will return structs from functions just fine. The downside is this can be a lot of memory copying back and forth:
struct arr {
int arr[50][50];
}
struct arr function(struct arr a) {
struct arr result;
/* operate on a.arr[i][j]
storing into result.arr[i][j] */
return result;
}
You can return a pointer to your array. This pointer must point to memory you allocate with malloc(3) for the array. (Or another memory allocation primitive that doesn't allocate memory from the stack.)
int **function(int param[][50]) {
int arr[][50] = malloc(50 * 50 * sizeof int);
/* store into arr[i][j] */
return arr;
}
You can operate on the array pointer passed into your function and modify the input array in place.
void function(int param[][50]) {
/* operate on param[i][j] directly -- destroys input */
}
You can use a parameter as an "output variable" and use that to "return" the new array. This is best if you want the caller to allocate memory or if you want to indicate success or failure:
int output[][50];
int function(int param[][50], int &output[][50]) {
output = malloc(50 * 50 * sizeof int);
/* write into output[i][j] */
return success_or_failure;
}
Or, for the caller to allocate:
int output[50][50];
void function(int param[][50], int output[][50]) {
/* write into output[i][j] */
}
You cannot return an array from a function.
You have several options:
wrap arrays inside structs
struct wraparray {
int array[42][42];
};
struct wraparray foobar(void) {
struct wraparray ret = {0};
return ret;
}
pass the destination array, as a pointer to its first element (and its size), to the function; and change that array
int foobar(int *dst, size_t rows, size_t cols, const int *src) {
size_t len = rows * cols;
while (len--) {
*dst++ = 42 + *src++;
}
return 0; /* ok */
}
// example usage
int x[42][42];
int y[42][42];
foobar(x[0], 42, 42, y[0]);
change the original array
int foobar(int *arr, size_t rows, size_t cols) {
size_t len = rows * cols;
while (len--) *arr++ = 0;
return 0; /* ok */
}
char **foo(const char * const * bar, size_t const *bar_len, size_t len0) {
size_t i;
char** arr = malloc(sizeof(char *) * len0);
for (i = 0; i < len0; ++i) {
arr[i] = malloc(bar_len[i]);
memcpy(arr[i], bar[i], bar_len[i]);
}
/* do something with arr */
return arr;
}
Somewhere else in your code:
char **pp;
size_t *pl;
size_t ppl;
/* Assume pp, pl are valid */
char **pq = foo(pp, pl, ppl);
/* Do something with pq */
/* ... */
/* Cleanup pq */
{
size_t i;
for (i = 0; i < ppl; ++i)
free(pq[i]);
free(pq);
}
Because you're passing by-pointer instead of by-value and you want to write to the input array, you have to make a copy of it.
Here's another example. Tested and works.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void test(char**,unsigned int,unsigned int);
const unsigned int sz_fld = 50 + 1;
const unsigned int sz_ffld = 10;
int main(void) {
char fld[sz_ffld][sz_fld];
for (unsigned char i=0;i<sz_ffld;++i) {
strcpy(fld[i],"");
}
strcpy(fld[0],"one");
strcpy(fld[1],"two");
strcpy(fld[2],"three");
char** pfld = malloc(sz_ffld*sizeof(char*));
for (unsigned int i=0;i<sz_ffld;++i) {
*(pfld+i) = &fld[i][0];
}
test(pfld,sz_ffld,sz_fld);
printf("%s\n",fld[0]);
printf("%s\n",fld[1]);
printf("%s\n",fld[2]);
free(pfld);
return(0);
}
void test(char** fld,unsigned int m,unsigned int n) {
strcpy(*(fld+0),"eleven");
strcpy(*(fld+1),"twelve");
return;
}
Note the following:
For compiling, I am using gcc with the C99 option.
I defined the function to include the two sizes information, but I wrote very basic code and am not actually using the information at all, just the strcpy(), so this certainly is not security-safe code in any way (even though I'm showing the "m" and "n" for such facility). It merely shows a technique for making a static 2D char array, and working with it in a function through the intermediate of an array of pointers to the "strings" of the array.
When you pass a 2D array to a function as a parameter, you need to explicitly tell it the size of the arrays second dimension
void MyFunction(array2d[][20]) { ... }
The following will do what you want. it will print "One" and "Ten". Also note that it is typed to the exact array dimensions of 10 and 8.
char my_array[10][8] =
{
{"One"},
{"Two"},
{"One"},
{"One"},
{"One"},
{"One"},
{"One"},
{"One"},
{"Nine"},
{"Ten"},
};
void foo ( char (**ret)[10][8] )
{
*ret = my_array;
}
void main()
{
char (*ret)[10][8];
foo(&ret);
printf("%s\r\n", (*ret)[0] )
printf("%s\r\n", (*ret)[9] )
}
The original question was about RETURNING the array, so I'm updating this to show returning a value. You can't "return an array" directly, but you CAN make a typedef of an array and return that...
char my_array[10][8];
typedef char ReturnArray[8];
ReturnArray* foo()
{
return my_array;
}