Hello I am new to C and I need someone to explain concepts to me. I am a JAVA programmer and I am trying to write a program in C. My current issue is trying to initialize an array with an unknown number. I know in C an array has to be initialized with a number instead of a variable like you can in Java. My question is if I can do this in Java:
int i = 0;
char array [i];
void f(){
\\some code
i++;
}
How can I do this in C? I'm trying to fill an array with certain strings that I get from a file. I don't know how many I will be getting from the file however. I have tried reading about malloc but in one tutorial it says:
int *pointer;
pointer=malloc(2*sizeof(int));
is equivalent to
int array[2];
But I'm looking for a way to do this while increment the array.
First to mention, malloc() and family is used for dynamic (runtime) memory allocation whereas int arr[2] usually denotes compile time memory allocation. They are not exactly equivalent.
However, if you want to resize the allocated memory on-the-fly, you're on right track. What you need to do next is to use realloc() to re-size the previously allocated memory location.
You can read the man page for more details.
Also, while using dynamic memory in C, you need to keep in mid that there is no garbage collector in C. You need to free() up every bit of memory allocated by you.
I know in C an array has to be initialized with a number instead of a variable like you can in Java
In C99 and beyond, variable initiated arrays are available.
My current issue is trying to initialize an array with an unknown number.
and:
But I'm looking for a way to do this while increment the array.
If you have an unknown number of elements at run-time, you can write a function to create (and free) memory, passing the relevant arguments as you need them. Here is an example of a function to create (and free) a 2 dimensional array of ints:
int ** Create2Dint(int **arr, int cols, int rows)
{
int space = cols*rows;
int y;
arr = calloc(space, sizeof(int));
for(y=0;y<cols;y++)
{
arr[y] = calloc(rows, sizeof(int));
}
return arr;
}
void free2DInt(int **arr, int cols)
{
int i;
for(i=0;i<cols; i++)
if(arr[i]) free(arr[i]);
free(arr);
}
If, during execution, you need to change the allocation of memory (change the size of the array) you can use realloc(), implemented here in similar fashion:
int ** Realloc2D(int **arr, int cols, int rows)
{
int space = cols*rows;
int y;
arr = realloc(arr, space*sizeof(int));
for(y=0;y<cols;y++)
{
arr[y] = calloc(rows, sizeof(int));
}
return arr;
}
Usage example:
(execute with two integer command line arguments, both > 0)
int main(int argc, char *argv[])
{
int **array = {0};
int cols, rows;
cols = atoi(argv[1]);
rows = atoi(argv[2]);
array = Create2Dint(array, cols, rows);
//Do stuff here to use array
//Memory requirements change during runtime:
cols += 20;
rows += 50;
array = Realloc2D(array, cols, rows);
//use array again...
//When you are finished with the memory, free it:
free2DInt(array, cols);
return 0;
}
Related
I want to use a struct to contain some data and passing them between different functions in my program,this struct has to contain a dynamic 2D array (i need a matrix) the dimensions change depending on program arguments.
So this is my struct :
struct mystruct {
int **my2darray;
}
I have a function that read numbers from a file and has to assign each of them to a cell of the struct array.
I tried doing this :
FILE *fp = fopen(filename, "r");
int rows;
int columns;
struct mystruct *result = malloc(sizeof(struct mystruct));
result->my2darray = malloc(sizeof(int)*rows);
int tmp[rows][columns];
for(int i = 0;i<rows;i++) {
for(int j = 0;j<columns;j++) {
fscanf(fp, "%d", &tmp[i][j]);
}
result->my2darray[i]=malloc(sizeof(int)*columns);
memcpy(result->my2darray[i],tmp[i],sizeof(tmp[i]));
}
But this is giving me a strange result : all the rows are correctly stored except for the first.
(I'm sure that the problem is not in the scanning of file).
While if i change the fourth line of code in this :
result->my2darray = malloc(sizeof(int)*(rows+1));
it works fine.
Now my question is why this happens?
Here's an answer using some "new" features of the language: flexible array members and pointers to VLA.
First of all, please check Correctly allocating multi-dimensional arrays. You'll want a 2D array, not some look-up table.
To allocate such a true 2D array, you can utilize flexible array members:
typedef struct
{
size_t x;
size_t y;
int flex[];
} array2d_t;
It will be allocated as a true array, although "mangled" into a single dimension:
size_t x = 2;
size_t y = 3;
array2d_t* arr2d = malloc( sizeof *arr2d + sizeof(int[x][y]) );
Because the problem with flexible array members is that they can neither be VLA nor 2-dimensional. And although casting it to another integer array type is safe (in regards of aliasing and alignment), the syntax is quite evil:
int(*ptr)[y] = (int(*)[y]) arr2d->flex; // bleh!
It would be possible hide all this evil syntax behind a macro:
#define get_array(arr2d) \
_Generic( (arr2d), \
array2d_t*: (int(*)[(arr2d)->y])(arr2d)->flex )
Read as: if arr2d is a of type array2d_t* then access that pointer to get the flex member, then cast it to an array pointer of appropriate type.
Full example:
#include <stdlib.h>
#include <stdio.h>
typedef struct
{
size_t x;
size_t y;
int flex[];
} array2d_t;
#define get_array(arr2d) \
_Generic( (arr2d), \
array2d_t*: (int(*)[(arr2d)->y])(arr2d)->flex )
int main (void)
{
size_t x = 2;
size_t y = 3;
array2d_t* arr = malloc( sizeof *arr + sizeof(int[x][y]) );
arr->x = x;
arr->y = y;
for(size_t i=0; i<arr->x; i++)
{
for(size_t j=0; j<arr->y; j++)
{
get_array(arr)[i][j] = i+j;
printf("%d ", get_array(arr)[i][j]);
}
printf("\n");
}
free(arr);
return 0;
}
Advantages over pointer-to-pointer:
An actual 2D array that can be allocated/freed with a single function call, and can be passed to functions like memcpy.
For example if you have two array2d_t* pointing at allocated memory, you can copy all the contents with a single memcpy call, without needing to access individual members.
No extra clutter in the struct, just the array.
No cache misses upon array access due to the memory being segmented all over the heap.
The code above never sets rows and columns, so the code has undefined behavior from reading those values.
Assuming you set those values properly, this isn't allocating the proper amount of memory:
result->my2darray = malloc(sizeof(int)*rows);
You're actually allocating space for an array of int instead of an array of int *. If the latter is larger (and it most likely is) then you haven't allocated enough space for the array and you again invoke undefined behavior by writing past the end of allocated memory.
You can allocate the proper amount of space like this:
result->my2darray = malloc(sizeof(int *)*rows);
Or even better, as this doesn't depend on the actual type:
result->my2darray = malloc(sizeof(*result->my2darray)*rows);
Also, there's no need to create a temporary array to read values into. Just read them directly into my2darray:
for(int i = 0;i<rows;i++) {
result->my2darray[i]=malloc(sizeof(int)*columns);
for(int j = 0;j<columns;j++) {
fscanf(fp, "%d", &result->my2darray[i][j]);
}
}
In your provided code example, the variables rows and columns have not been initialized before use, so they can contain anything, but are likely to be equal to 0. Either way, as written, the results will always be unpredictable.
When a 2D array is needed in C, it is useful to encapsulate the memory allocation, and freeing of memory into functions to simplify the task, and improve readability. For example, in your code the following line will create an array of 5 pointers, each pointing to 20 int storage locations: (creating 100 index addressable int locations.)
int main(void)
{
struct mystruct result = {0};
result.my2darray = Create2D(5, 20);
if(result.my2darray)
{
// use result.my2darray
result.my2darray[0][3] = 20;// for simple example, but more likely in a read loop
// then free result.my2darray
free2D(result.my2darray, 5);
}
return 0;
}
Using the following two functions:
int ** Create2D(int c, int r)
{
int **arr;
int y;
arr = calloc(c, sizeof(int *)); //create c pointers (columns)
for(y=0;y<c;y++)
{
arr[y] = calloc(r, sizeof(int)); //create r int locations for each pointer (rows)
}
return arr;
}
void free2D(int **arr, int c)
{
int i;
if(!arr) return;
for(i=0;i<c;i++)
{
if(arr[i])
{
free(arr[i]);
arr[i] = NULL;
}
}
free(arr);
arr = NULL;
}
Keep in mind that what you have created using this technique is actually 5 different pointer locations each pointing to a set of 20 int locations. This is what facilitates the use of array like indexing, i.e. we can say result.my2darray[1][3] represents the second column, forth row element of a 5X20 array, when it is not really an array at all.
int some_array[5][20] = {0};//init all elements to zero
Is what is commonly referred to in C an int array, also allowing access to each element via indexing. In actuality (Even though commonly referred to as an array.) it is not an array. The location of elements in this variable are stored in one contiguous location in memory.
|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0... (~ 82 more)
But C maintains the locations such that they are all indexable as an 2D array.
I've been on the site for hours now and I read a lot of new techniques and programmed defined functions,but I'm still a little confused on how to apply it to my own program. I trying to start slow and build a checkers game. So first I created a function to create a Board. Of course i researched and read that C doesn't easily allow for you to return char arrays from functions. So I read up on memory allocation using malloc or calloc.
So my first mistake...
void printBoard(char arr[9][19]);
int makeMove(char arr[11][23], int king, struct player P, char player);
char *createBoard();
char Rows[8]="ABCDEFGH";
int main()
{
int x, y;
int isKing = 1;
char checkerBoard[9][19];
checkerBoard[9][19] = createBoard();
printBoard(checkerBoard);
/* ... */
}
and then...
void printBoard(char array[9][19])
{
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 19; j++)
printf("%c", array[i][j]);
}
printf("\n");
};
char * createBoard()
{
// where I put code
return checkerBoard[9][19];
}
I purposely left out the code inside createBoard() it was a lot. So when using void *malloc(size_t size), I know i need to specify the bytes in size like 4 * sizeof(char)but doesn't the size the array go in there also? Also, would changing the checkerBoard array to static be better?
Its great that you are reading about arrays in C. You mentioned in your question that you read that "C doesn't allow you to easily return arrays from functions". In C, when you declare a statically sized array inside of a function, that array in memory exists on the stack. Every function has it's own stack, so when you return from a function, that memory can be reused again.
When you allocate space with malloc and calloc, that allocates space on the heap. Here is an article with more information: Stack Vs Heap.
Now onto your checkerboard issue, what you want is an array of arrays. You can think of each square on the checkerboard as being an individual character. Let's say our checkerboard had one row.
char * row_zero = malloc(sizeof(char) * 15); //row_zero has a length of 15
Checkerboards obviously have more than one row though, what about 9?
char * row_zero = malloc(sizeof(char) * 15);
char * row_one = malloc(sizeof(char) * 15);
.
.
char * row_eight = malloc(sizeof(char) * 15);
While you can do this, it will be incredibly messy. So instead of creating individual rows, you can simply have a pointer to an array of pointers.
char ** my_checkerboard = malloc(sizeof(char*) * 9); //has 9 rows.
I will let you figure out how to finish making your board.
I am relatively new to C and have coded (or more precise: copied from here and adapted) the functions below. The first one takes a numpy array and converts it to a C int array:
int **pymatrix_to_CarrayptrsInt(PyArrayObject *arrayin) {
int **result, *array, *tmpResult;
int i, n, m, j;
n = arrayin->dimensions[0];
m = arrayin->dimensions[1];
result = ptrvectorInt(n, m);
array = (int *) arrayin->data; /* pointer to arrayin data as int */
for (i = 0; i < n; i++) {
result[i] = &array[i * m];
}
return result;
}
The second one is used within the first one to allocate the necessary memory of the row vectors:
int **ptrvectorInt(long dim1, long dim2) {
int **result, i;
result = malloc(dim1 * sizeof(int*));
for (i = 0; i < dim1; i++) {
if (!(result[i] = malloc(dim2 * sizeof(int)))){
printf("In **ptrvectorInt. Allocation of memory for int array failed.");
exit(0);
}
}
return result;
}
Up to this point everything works quite fine. Now I want to free the memory occupied by the C array. I have found multiple threads about how to do it, e.g. Allocate and free 2D array in C using void, C: Correctly freeing memory of a multi-dimensional array, or how to free c 2d array. Inspired by the respective answers I wrote my freeing function:
void free_CarrayptrsInt(int **ptr, int i) {
for (i -= 1; i >= 0; i--) {
free(ptr[i]);
}
free(ptr);
}
Nontheless, I found out that already the first call of free fails - no matter whether I let the for loop go down or up.
I looked for explenations for failing free commands: Can a call to free() in C ever fail? and free up on malloc fails. This suggests, that there may have been a problem already at the memory allocation. However, my program works completely as expected - except memory freeing. Printing the regarded array shows that everything should be fine. What could be the issue? And even more important: How can I properly free the array?
I work on a Win8 64 bit machine with Visual Studio 10 64bit compiler. I use C together with python 3.4 64bit.
Thanks for all help!
pymatrix_to_CarrayptrsInt() calls ptrvectorInt() and this allocation is made
if (!(result[i] = malloc(dim2 * sizeof(int)))){
then pymatrix_to_CarrayptrsInt() writes over that allocation with this assignment
result[i] = &array[i * m];
causing a memory leak. If array is free()'d then attempting to free() result will fail
I am trying to dynamically allocate a 2D array, put some values, and print output. However it seems that I am making mistake in getting input to program in atoi() function.
Basically when we assign a static 2D array, we declare it as say int a [3][3]. So 3*3 units if int, that much memory gets allocated. Is same thing holds for allocating dynamic array as well?
Here is my code:
#include<stdio.h>
#include<stdlib.h>
int main(int arg,char* argv)
{
int rows = atoi(argv[1]);
int col = atoi(argv[2]);
int rows =3;
int col=3;
int i,j;
int (*arr)[col] = malloc(sizeof (*arr)*rows);
int *ptr = &(arr[0][0]);
int ct=1;
for (i=0;i<rows;i++)
{
for(j=0;j<col;j++)
{
arr[i][j]=ct;
ct++;
}
}
printf("printing array \n");
for (i=0;i<rows;i++)
{
for(j=0;j<col;j++)
{
printf("%d \t",arr[i][j]);
}
printf("\n");
}
free(arr);
return (0);
}
Program crashes in runtime. Can someone comment?
The first issue I see is this line:
int (*arr)[rows][col] = malloc(sizeof (*arr) * rows);
This is not problematic at all because you are in fact allocating more memory than you need. This would suffice:
int (*arr)[rows][col] = malloc(sizeof (*arr));
sizeof *arr is enough because *arr is of type int [rows][cols]; the memory you want is exactly the size of that array. The sizeof operator, when applied to arrays, gives you the count for the whole array.
The main problem with your code, however, is how you use arr. You are indexing it with arr[i][j], but instead, you should be using (*arr)[i][j], because arr is not an array, it's a pointer to an array. You need to dereference it before any further indexing - as simple as that. arr[i][j] is equivalent to *(*(arr+i)+j). Note that i should be an offset into *arr, not an offset on arr. That's why you need to dereference arr before indexing.
Since you're already using variable-length arrays, you may take advantage of that:
int (*arr)[col] = malloc(sizeof *arr * rows);
This way you can simply access elements with the usual syntax arr[i][j] without worrying about pointers and dereferences, pointer arithmetic will do all the work for you.
Also since indexes start from 0 your tests should look like i < rows and j < col.
And you have some minor errors for the wrong main declaration and the second printf.
For a multitude of reasons, I'd like to allocate multidimensional arrays in contiguous chunks of memory. I can do this by allocating them manually, eg:
t.versions=(char***)malloc(sizeof(char**)*4);
t.versions[0]=(char**)malloc(sizeof(char*)*t.size*4);
t.versions[0][0]=(char*)calloc(t.size*t.size*4,sizeof(char));
for (i=1; i<t.size*4; ++i)
t.versions[0][i]=t.versions[0][i-1]+t.size;
for (i=1; i<4; ++i)
t.versions[i]=t.versions[i-1]+t.size;
Among other benefits, this solution simplifies freeing the allocated memory:
void contiguous_array_free(void** ptr, int depth)
{
int *ptr_d;
ptr_d=(int*)*ptr;
if (depth>1)
contiguous_array_free((void**)ptr_d, depth-1);
free(ptr);
}
//(elsewhere in the code)
contiguous_array_free((void**)(*tile).versions, 3);
Now, I've got a small problem with allocating those arrays - while the approach posted above does work, ideally I'd like to have a generic solution that allows me to allocate those arrays with a single function call.
However, my attempt to achieve that goal results in the program crashing every time the array contents are used.
//dimension points to a 1-dimensional array of integers
//specifying the size in each array dimension
void* contiguous_array_alloc(int* dimension, int depth, int size)
{
int i;
char** ptr;
if (depth==1)
{
ptr=(char**)malloc(*dimension*size);
return ptr;
}
ptr=(char**)malloc(*dimension*sizeof(char*));
*(dimension+1)*=*dimension;
ptr[0]=(char*)contiguous_array_alloc(dimension+1, depth-1, size);
*(dimension+1)/=(*dimension);
for (i=1; i<*dimension; ++i)
ptr[i]=ptr[i-1]+(*(dimension+1)*size);
return (void*)ptr;
}
//(later in the code) (
int dimension[3];
dimension[0]=4;
dimension[1]=t.size;
dimension[2]=t.size;
t.versions=(char***)contiguous_array_alloc(&dimension[0], 3, sizeof(char));
Adding some debug messages into the code seems to indicate the elements are allocated correctly:
Allocating [4][9][9] array of size 1 elements;
malloc()ating 16 byte array for 4 pointers;
Allocated pointer array to level 2 at 003E29E8;
Allocating [36][9] array of size 1 elements;
malloc()ating 144 byte array for 36 pointers;
Allocated pointer array to level 1 at 003E5728;
Allocating [324] array of size 1 elements;
324 byte data array at 003E57C0;
Pointed data at 003E57C0;
increasing every pointer by 9;
Returning allocated array;
Pointed data at 003E5728;
increasing every pointer by 9;
Returning allocated array;
Allocated contiguous array at 003E29E8;
What is causing this behavior? I've checked the code several times and have no idea what I've done wrong.
I think there is something wrong for ptr[i]=ptr[i-1]+(*(dimension+1)*size); this kind of pointer operation usage does not make sense. I modified the code as below which passed the test for 4-dimension array.
//dimension points to a 1-dimensional array of integers
//specifying the size in each array dimension
void* contiguous_array_alloc(int* dimension, int depth, int size) {
int i;
if (depth==2) {
char ** ptr=(char **)malloc(*dimension * sizeof(void*));
ptr[0]=(char *)malloc(*dimension * dimension[1] * size);
for (i=1; i<*dimension; ++i) {
ptr[i]=ptr[i-1]+(*(dimension+1) * size);
}
return (void*)ptr;
} else {
void ***ptr=(void***)malloc(*dimension * sizeof(void*));
*(dimension+1)*=(*dimension);
ptr[0]=contiguous_array_alloc(dimension+1, depth-1, size);
*(dimension+1)/=(*dimension);
for (i=1; i<*dimension; ++i) {
ptr[i]=ptr[i-1]+(*(dimension+1));
}
return (void*)ptr;
}
}
All you need for an a ⨉ b ⨉ c ⨉ d array of int is:
int (*p)[b][c][d] = calloc(a, sizeof *p);