I have written a function that allocates and initialises a 2D array, like this -
static state **symbols;
void initNFAStates()
{
int i,j;
numStates = 256;
symbols = (state**)malloc(numStates * sizeof(char));
for(i = 0;i < numStates;i++)
{
symbols[i] = (state*)malloc(NUMSYMBOLS * sizeof(state));
for(j = 0;j < NUMSYMBOLS;j++)
symbols[i][j] = 0;
}
}
and a function to print this array, like this -
void printNFAStateTable()
{
int i, j;
for(i = 0;i < numStates;i++)
{
printf("%d \t",i);
for(j = 0;j < NUMSYMBOLS;j++)
printf("%ld",symbols[i][j]);
printf("\n");
}
}
When called consecutively from the main() function, they both work fine. However, the code as follows results in a segfault after reading only the first 32 lines from the array.
int main(int argc, char **argv)
{
int i;
clock_t begin, end;
double timeTaken;
currNFAState = 0;
initNFAStates();
if(getChars(argc,argv) != NULL)
{
printNFAStateTable();
begin = clock();
regex();
...
Similarly, the printf() function causes the same issue, but only when printing a floating point number -
int main(int argc, char **argv)
{
int i;
clock_t begin, end;
double timeTaken;
currNFAState = 0;
initNFAStates();
printf("A floating point number - %f",0.0124f);
printNFAStateTable();
...
I am aware this has to do with the symbols array being static, as the issue does not appear when the array is global. Could anyone explain why this occurs?
Given this declaration:
static state **symbols;
This allocation is incorrect:
symbols = (state**)malloc(numStates * sizeof(char));
The type of *symbols is state *; this is the type of the elements of the array you are dynamically allocating, and I feel confident in asserting that pointers on your machine are larger than char is. This would be a more appropriate allocation:
symbols = malloc(numStates * sizeof(*symbols));
(Note that you do not need to cast the return value of malloc(), and there are good reasons not to do so.)
Having not allocated memory sufficient for all the pointers you want to use, your program exhibits undefined behavior when it tries to access elements at indices that would fall outside the bounds of the allocation. That UB very easily could manifest in the form of library functions modifying memory you did not expect them to modify.
This is not doing what you expect:
symbols[i][j] = 0;
The reason is that this assumes a singularly allocated block of memory organized as a 2D array. That's not what you've created.
Your code indicates the first dimension is sized at 256, which would look like this:
state symbols[256][NUMSYMBOLS];
If you allocated globally or on the stack. This would be a single block of RAM sized as 256 * NUMSYBOLS * sizeof( state ), where each row is advanced NUMSYMBOLS * sizeof( state ).
What you're doing, however, is create an a array of pointers in one block of RAM, and then allocating additional blocks of RAM for each row. They are unrelated such that access is not going to work using the 2D array syntax.
What you need is first to access the pointer to the row, conceptually:
state *state_row = symbols[ i ];
This gives you the row. Now, get the column;
stat * state_cell = state_row[ j ];
This is expanded to show how to think about it, you can easily choose other specific means of accessing the appropriate cells.
Related
I'm a student learning C and I was puttering around with arrays of strings and malloc().
I have the following code that is supposed to load an array of strings (statically created) with dynamically created strings (please forgive / correct me if my terminology does not align with the code I have).
The problem is, once I go to free that memory, I get the following error: free(): invalid pointer
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#define RAM_SIZE 5
char* ram [RAM_SIZE];
int next_free_cell = 0;
void freeAndNullRam(){
for (int i = 0 ; i < RAM_SIZE ; i++){
printf("%d\n", i);
free(ram[i]);
ram[i] = NULL;
}
}
int main(int argc, const char *argv[])
{
for (int i= 0; i < RAM_SIZE; i++){
ram[i] = (char*)malloc(sizeof(char*)*5);
ram[i] = "aaaa";
}
for (int i= 0; i < RAM_SIZE; i++){
int empty = (ram[i] ==NULL);
if(!empty){
printf("%s\n", ram[i]);
}
}
freeAndNullRam();
for (int i= 0; i < RAM_SIZE; i++){
int empty = (ram[i] ==NULL);
printf("%d\n", empty);
}
return 0;
}
I know the issue is definitely in the freeAndNullRam() function (obviously), but I don't understand why. My understanding is that at compile time, an array of 5 pointers to char arrays is created, but to actually fill the cells of the array, I need to malloc them some memory. Why does the program complain when I free the pointers in the array, but not when I give them memory?
Thanks!
ram[i] = "aaaa"; reassigns the pointers at a[i] to point to static memory, discarding the result of malloc. Later on you pass those pointers to free, which fails because they were not the result of an *alloc function.
Use strcpy to instead copy the string from static memory into your allocated destination.
strcpy(a[i], "aaaa")
Here's a reworked version of your code to be more idiomatic C:
#include <stdio.h>
#include <stdlib.h>
// Create an array of arbitrary size
char* alloc_array(size_t size) {
// calloc() will give you a pre-zeroed (NULL) allocation, malloc() may not
return calloc(size, sizeof(char*));
}
// Clears out all entries in the array, leaving only NULL
void clear_array(char* array, size_t size) {
for (size_t i = 0; i < size; ++i) {
// free(NULL) doesn't do anything, and is easier than a test
free(array[i]);
array[i] = NULL;
}
}
// Clears, then frees the array
void free_array(char* array, size_t size) {
clear_array(array, size);
free(array);
}
int main(int argc, const char *argv[])
{
// Whenever possible use local variables, not global variables
size_t size = 5;
char* entries = alloc_array(size);
for (size_t i = 0; i < size; ++i) {
// Make a copy with strdup() so this can be released with free()
// later on. A string like "..." is static, it was never allocated.
entries[i] = strdup("aaaa");
}
for (size_t i = 0; i < size; i++) {
// Express conditions in the if statment directly
if (entries[i] != NULL) {
printf("%s\n", ram[i]);
}
}
clear_array(entries);
for (size_t i = 0; i < size; i++) {
printf("%d\n", entries[i] != NULL);
}
// Don't forget to release any allocated memory.
free_array(entries);
return 0;
}
There's a lot of bad habits in your original code you should work to expunge as quickly as possible so these things don't take root. In particular, global variables are a huge problem that need to be avoided.
One thing to remember is unless something was explicitly allocated with malloc() or a variant like calloc(), or was given to your code with an understanding that it was allocated in such a fashion, you should not call free() on it.
Not every pointer was allocated dynamically, and not every dynamically allocated pointer was allocated with malloc(). Some C code can be very confusing as a result of this.
C's syntax strongly suggests that "aaaa" is a "string". People even talk of this syntax that way: they call it "strings". But "aaaa" is nothing such. It's the unfortunately named string literal, which is not a string - neither in C nor in C++. A char * is not a string either - it's a pointer-typed value. It's used to represent strings, but itself is not a string - not even close.
You have quite reasonably expected that "aaaa" might behave like any other rvalue of the "obvious" type. Alas, while 1 is an integer literal of type int, "aaaa" is a string literal of a pointer type const char * - its value is not a string, but a pointer!
It's as if when you wrote 42, C gave you a const int * pointing to 42. That's what "string" literals do. That's the awfully deplorable side of C :(
In C++, there actually is a string type (std::string), and you can even write literals of that type with a new syntax introduced in C++11: "aaaa"s is an rvalue* of type std::string, and you can assign them exactly as you would expect of any other value type like int.
Since you're already thinking a bit like in C++, perhaps you can investigate that language next. It takes much less effort to do plenty of basic things in C++ compared to C.
*technically rvalue reference
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 using an array of structs and then set up the elements like the following:
#include <stdio.h>
#include <stdlib.h>
typedef struct _point {
char s;
unsigned int x;
unsigned int y;
} point;
point* vehicle;
int main(int argc, char *argv[]) {
/* 26 Vehicles */
vehicle = malloc(26*sizeof(point*));
for (int i = 0; i < 26; i++) {
vehicle[i].s = ' ';
}
/* Print already existing vehicles */
for (int i = 0; i < 26; i++) {
if (vehicle[i].s != ' ') {
printf("%c: x=%d y=%d\n", vehicle[i].s, vehicle[i].x, vehicle[i].y);
}
}
return 0;
}
NOTE: this is not the actual code (which is too big to post) but the set up of the array and structs is the same.
As you can see, I set every vehicle[i].s to the space character, but the loop prints the following (not it this example code but in my actual code):
: x=32215344 y=0
P: x=0 y=33
: x=2105376 y=0
Question: how can it be that after the first loop, some elements are modified in the "background" without assigning them in the code? Or can some other malloc operations overwrite/reallocate the memory?
The problem, as I see it is in
vehicle = malloc(26*sizeof(point*));
you're allocating memory for the pointer-to-the-data-type type, whereas you should be allocating for the data type itself.
To elaborate, you want to allocate memory for 26 elements of type point (i.e., struct _point), not 26 point *.
Change
vehicle = malloc(26*sizeof(point));
or, for better,
vehicle = malloc(26*sizeof * vehicle);
Otherwise, you're running short of allocated memory when you try to dererference the pointer to access ns of instances. So, you end up accessing out-of-bound memory which causes undefined behavior.
That said, just an advice, if you know the size to be allocated beforehand, (26, for example), don't use dynamic memory, there's no need for it. Use an array.
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;
}