How to allocate contiguous 2D array of strings in C - c

I am new in whole C programming thing (comming from Java), and honestly its really confusing. Ok to the problem I am trying to allocate contigous chunk of data for my 2D array of strings (Guessing its something like 3D array??). All I have is this i believe contiguous allocation for Array of strings?
Can someone help me out with 2D array please?
And yes I know size before running the program, its defined so ROWS for rows, COLS for columns and NAME for length of string.
char **people = malloc(COLS * sizeof(char *));
people[0] = malloc(COLS * NAME);
for(int i = 1; i < COLS; i++)
people[i] = people[0] + i * NAME;

If you actually know the size of the array before running the program, you don't need to dinamically allocate the memory with malloc, you could create a 2D static array. In your case, as it is a 2D array of strings, it could be declared as char * array[ROWS][COLS], and then you could asign a string to a specific element this way: array[nrow][ncol]="Your String".

C, unlike Java, actually has a concept of multidimensional arrays; so unless there's a specific reason you want a char * * *, you might prefer to write:
char (*people)[COLS][NAME] = malloc(ROWS * sizeof(*people));
which sets people to be a pointer to the first of ROWS dynamically-allocated two-dimensional character arrays.
Due to pointer "decay", where an expression of array type will double as a pointer to the first element of the array, you can use people very much as if it were a char * * *; for example, people[3][4] will point to the string in row 3, column 4. The only restriction is that you can't write something like people[3][4] = ... to suddenly change what string to point to. But it sounds like you don't want to do that, anyway?
Note: the above is assuming that you are intentionally using dynamic memory allocation. However, I do recommend you consider Sizigia's suggestion to use static memory, which is the same sort of storage as is used for global variables. If you write something like
static char people[ROWS][COLS][NAME];
then the memory will be allocated just once, at the start of the program, and reused by all calls to the function that declares it.

You can define a char * using typedef so it's better for you to understand the code. Then all you have to do is to dynamically allocate a 2D array of your defined type (in the example below, I defined it as a "string"):
typedef char * string;
string ** people;
people = malloc(ROWS * sizeof(string));
for(int i = 0; i < ROWS; i++){
people[i] = malloc(COLUMNS * sizeof(char));
}
You can access it using the normal array sintax, people[i][j].

Related

How to return a char** in C

I've been trying for a while now and I can not seem to get this working:
char** fetch (char *lat, char*lon){
char emps[10][50];
//char** array = emps;
int cnt = -1;
while (row = mysql_fetch_row(result))
{
char emp_det[3][20];
char temp_emp[50] = "";
for (int i = 0; i < 4; i++){
strcpy(emp_det[i], row[i]);
}
if ( (strncmp(emp_det[1], lat, 7) == 0) && (strncmp(emp_det[2], lon, 8) == 0) ) {
cnt++;
for (int i = 0; i < 4; i++){
strcat(temp_emp, emp_det[i]);
if(i < 3) {
strcat(temp_emp, " ");
}
}
strcpy(emps[cnt], temp_emp);
}
}
}
mysql_free_result(result);
mysql_close(connection);
return array;
Yes, I know array = emps is commented out, but without it commented, it tells me that the pointer types are incompatible. This, in case I forgot to mention, is in a char** type function and I want it to return emps[10][50] or the next best thing. How can I go about doing that? Thank you!
An array expression of type T [N][M] does not decay to T ** - it decays to type T (*)[M] (pointer to M-element array).
Secondly, you're trying to return the address of an array that's local to the function; once the function exits, the emps array no longer exists, and any pointer to it becomes invalid.
You'd probably be better off passing the target array as a parameter to the function and have the function write to it, rather than creating a new array within the function and returning it. You could dynamically allocate the array, but then you're doing a memory management dance, and the best way to avoid problems with memory management is to avoid doing memory management.
So your function definition would look like
void fetch( char *lat, char *lon, char emps[][50], size_t rows ) { ... }
and your function call would look like
char my_emps[10][50];
...
fetch( &lat, &lon, my_emps, 10 );
What you're attempting won't work, even if you attempt to cast, because you'll be returning the address of a local variable. When the function returns, that variable goes out of scope and the memory it was using is no longer valid. Attempting to dereference that address will result in undefined behavior.
What you need is to use dynamic memory allocation to create the data structure you want to return:
char **emps;
emps = malloc(10 * sizeof(char *));
for (int i=0; i<10; i++) {
emps[i] = malloc(50);
}
....
return emps;
The calling function will need to free the memory created by this function. It also needs to know how many allocations were done so it knows how many times to call free.
If you found a way to cast char emps[10][50]; into a char * or char **
you wouldn't be able to properly map the data (dimensions, etc). multi-dimensional char arrays are not char **. They're just contiguous memory with index calculation. Better fit to a char * BTW
but the biggest problem would be that emps would go out of scope, and the auto memory would be reallocated to some other variable, destroying the data.
There's a way to do it, though, if your dimensions are really fixed:
You can create a function that takes a char[10][50] as an in/out parameter (you cannot return an array, not allowed by the compiler, you could return a struct containing an array, but that wouldn't be efficient)
Example:
void myfunc(char emp[10][50])
{
emp[4][5] = 'a'; // update emp in the function
}
int main()
{
char x[10][50];
myfunc(x);
// ...
}
The main program is responsible of the memory of x which is passed as modifiable to myfunc routine: it is safe and fast (no memory copy)
Good practice: define a type like this typedef char matrix10_50[10][50]; it makes declarations more logical.
The main drawback here is that dimensions are fixed. If you want to use myfunc for another dimension set, you have to copy/paste it or use macros to define both (like a poor man's template).
EDITa fine comment suggests that some compilers support variable array size.
So you could pass dimensions alongside your unconstrained array:
void myfunc(int rows, int cols, char emp[rows][cols])
Tested, works with gcc 4.9 (probably on earlier versions too) only on C code, not C++ and not in .cpp files containing plain C (but still beats cumbersome malloc/free calls)
In order to understand why you can't do that, you need to understand how matrices work in C.
A matrix, let's say your char emps[10][50] is a continuous block of storage capable of storing 10*50=500 chars (imagine an array of 500 elements). When you access emps[i][j], it accesses the element at index 50*i + j in that "array" (pick a piece of paper and a pen to understand why). The problem is that the 50 in that formula is the number of columns in the matrix, which is known at the compile time from the data type itself. When you have a char** the compiler has no way of knowing how to access a random element in the matrix.
A way of building the matrix such that it is a char** is to create an array of pointers to char and then allocate each of those pointers:
char **emps = malloc(10 * sizeof(char*)); // create an array of 10 pointers to char
for (int i = 0; i < 10; i++)
emps[i] = malloc(50 * sizeof(char)); // create 10 arrays of 50 chars each
The point is, you can't convert a matrix to a double pointer in a similar way you convert an array to a pointer.
Another problem: Returning a 2D matrix as 'char**' is only meaningful if the matrix is implemented using an array of pointers, each pointer pointing to an array of characters. As explained previously, a 2D matrix in C is just a flat array of characters. The most you can return is a pointer to the [0][0] entry, a 'char*'. There's a mismatch in the number of indirections.

Memory leak in C

I am using GTK, and I am not sure with malloc() function here. Valgrind gives me a memory leak, what I am doing bad?
at first I create pointer to pointer to pointer to GTK widget, because I need three dimensional array.
GtkWidget*** widgets;
and I am using malloc like this:
widgets = malloc((1)*sizeof(GtkWidget**));
for(i = 0; i<= l-1; i++) // l = 4 in my case
{
widgets[i] = malloc((1)*sizeof(GtkWidget*));
for(j = 0; j<=3; j++) // 4 is number of elements in this dimension
{
widgets[i][j] = malloc((1)*sizeof(GtkWidget));
}
}
and at the end I am doing this:
widgets[0][0] = gtk_menu_item_new_with_label("MyLabel");
gtk_menu_shell_append(GTK_MENU_SHELL(indicator_menu), widgets[0][0]);
my array can be smaller and bigger, so I am using dynamic allocation of array, my maximal array indexes are something like widgets[3][3].
I did not post whole code, because it is pretty long, I sent here just the parts for which was valgrind complaining to. What I am doing bad? thank you.
You're only allocating the size of a pointer, when you mean to allocate an array of pointers.
// this will allocate a single character pointer
char ** ptr = malloc(1 * sizeof(char *));
// this will allocate n character pointers
char ** ptr = malloc(n * sizeof(char *));
So if you want a two dimensional array of dimension NxM, you'll need to allocate an array of size N, then walk through that array from 0 to N-1 and allocate arrays of size M.
What you're doing now is assigning pointers returned from malloc to memory you don't own. Is what you actually want a two-dimensional array of pointers to GtkWidget structures?
Using l as a local variable is not a good idea. It is very easy to make a mistake between l and 1, in some editors they look very much the same.
widgets = malloc((l)*sizeof(GtkWidget**)); //is what you needed
iso
widgets = malloc((1)*sizeof(GtkWidget**));
Over here with syntax highlighting the problem immediately appears.
So another suggestion is to for sure use an editor with syntax highlighting

Declaring and Initializing 2D array of unknown size in C

I plan to create an 2D array of a pointer derived from typedef struct
Let's say the typedef struct is named "Items" and contains mixed variables of strings and integers.
I will declare two intvariables namely typenum and typetotal. These two integers will start off from Zero and adds up when the input data matches with certain function.
In the array,Items *type[][], basically type[][] is Items *type[typenum][typetotal] but I cannot do this since I will declare typenum and typetotal as zero at the declaration part.
I tried initializing the array through Items *type[][] = {{0},{0}} but this generates error.
Any advice? Some told me to use malloc() on this, but I simply do not know how.
*Using Tiny C on Windows
Use dynamic memory allocation.
Items **type;
type = malloc(sizeof (Items *) * typenum);
for (int i = 0; i < typenum; i++)
type[i] = malloc(sizeof Items) * typetotal);
You need to manually free the allocated memory after using the array.
for (int i = 0; i < typenum; i++)
free(types[i]);
free(types);
Here is a tutorial on it: http://www.eskimo.com/~scs/cclass/int/sx9b.html
If typenum and typetotal increase as your program runs be sure to use realloc, which will reallocate more memory and keep the contents. You'll need to allocate the first dimension of the array like this:
myArray = realloc(myArray, sizeof(Items*) * typenum);
and then allocate the second dimension for each of the first:
for(...)
myArray[i] = realloc(myArray[i], sizeof(Items) * typetotal);

C Program: regular versus ragged character-string arrays

I'm trying to write more efficient code in a C program, and I need some help getting my pointers and assignments correct. I've shown two methods below, each using the following declarations and strncpy:
int kk, arraysize;
char person_name[100] = "";
char * array_person_name, * array_param;
...
strncpy(person_name, "John Smith", 100);
arraysize = <this value is downloaded from database>;
...
Method A (rectangular array):
array_person_name = malloc( sizeof(char) * arraysize *100 );
array_param = malloc( sizeof(char) * arraysize * 2 );
for (kk = 0; kk < arraysize; kk++) {
strncpy(array_person_name[kk], person_name, 100);
strncpy(array_param[kk], "bt", 2);
}
Method B (ragged array):
for (kk = 0; kk < arraysize; kk++) {
array_person_name[kk] = &person_name;
array_param[kk] = "bt";
}
Notice that the arrays I'm trying to create place the same value into each element of the array. Method A is an (rectangular) array of arraysize elements, each element itself being an array of 100 characters. Method B attempts not to waste storage space by creating an (ragged) array of arraysize elements, where each element is a pointer-to-char.
QUESTION 1: Am I allocating memory (e.g. malloc) correctly in Method A?
QUESTION 2: Does the syntax look correct for Method B?
QUESTION 3: How do I allocate memory for the arrays in method B?
QUESTION 4: Am I correct that Method B is generally preferred?
You are pretty far off here. 1:yes, 2:no, 3:no, 4:yes. I'm not going to do it all, but here are a few hints.
You need space to store the strings and space to store pointers to the strings (the latter isn't strictly necessary for Method A). The first will have type char*, the second will have type char**.
For Method A, you are allocating the string storage correctly, but you need to allocate the storage for the string pointers correctly (hint: you need arraysize instances of a char* pointer). It then gets initialized to pointers which differ from each other by 100 characters.
For Method B, there is no easy way of allocating space to store the strings, as you don't know how much space you'll need. You could iterate through all the strings once just to count their length, or do one malloc per string, or use a fixed size chunk and allocate more when you run out.
Method B uses the same string storage pointer array as Method A. You need to assign the string pointers into the array once you know where they will go.

C: Dynamic array of pointers to array of structure

I have a structure and a bidimensional array of those structs:
typedef struct {
char exit_n;
char exit_s;
char exit_w;
char exit_e;
} room;
room map[MAP_WIDTH][MAP_HEIGHT];
I need an array of pointers those structs. The following code compiles, but I don't get the wanted result. Any help? This is getting really confused to me, any explanation would be appreciated
room *rooms;
rooms = (room*)malloc(sizeof(room*) * ROOM_NUM);
[..]
rooms[n] = map[room_x][room_y];
[..]
Actually, I think you want
room** rooms;
rooms = (room**)malloc(sizeof(room*) * ROOM_NUM);
[..]
rooms[n] = &map[room_x][room_y];
This gives you an array of pointers to your rooms.
I'm am pretty sure you want
sizeof(room)
You need to allocate enough space for the struct. You are only allocating for a pointer.
You also may need to allocate differently if you want a 2D array:
see here dynamic allocating array of arrays in C
The major issue I see is that you are using sizeof(room*). This means that you are taking the size of a pointer to a structure, which is not what you want. You want to allocate the size of the structure, so make that sizeof(room). Also, use calloc in this case, not malloc, as you are basically implementing the former's functionality by multiplying the number of rooms by the size of the room.
In your current code, rooms becomes an array of room structures, not an array of pointers. If you want an array of pointers that each point to your map array, you need another layer of indirection:
room** rooms = malloc(ROOM_NUM * sizeof *rooms);
// ...
rooms[n] = &map[room_x][room_y];
(Or you can use sizeof (room *) like your code has instead of sizeof *rooms; I prefer to write it that way to avoid duplicating type information.)
You need to allocate space for the pointers and for the rooms and then initialize the pointers to point to the rooms.
room *rooms;
room **prooms;
rooms = (room*)malloc((sizeof(room) + sizeof(room*)) * ROOM_NUM);
prooms = (room**)(&rooms[ROOM_NUM]);
for (int ii = 0; ii < ROOM_NUM; ++ii)
prooms[ii] = &rooms[ii];
If I understand correctly, you want an array of pointers to all the room values in map. Since there are MAP_WIDTH*MAP_HEIGHT such values, we need that many pointers:
room *rooms[MAP_WIDTH*MAP_HEIGHT];
The above declares rooms as an array of pointers.
Now, to assign the values:
size_t i;
size_t j;
for (i=0; i < MAP_WIDTH; ++i)
for (j=0; j < MAP_HEIGHT; ++j)
rooms[i*MAP_HEIGHT+j] = &map[i][j];
We basically find the address of each element in map, and store it in the correct entry in rooms.
Is this what you wanted?

Resources