I have a structure called container that has two fields: labels and linked_to_containers; The field labels is designed to be a 2-dimensional array of int, and the field linked_to_containers is designed to be a 2-dimensional array of int pointers. On top of this, I also have an array of struct container that are dynamically created in the initiation program. I have the following code written down, but one thing I'm unsure about is the first malloc I used inside of the function container_init(). As the struct container still does not have its size initialized, is this the right way to do malloc for creating an array of struct container?
Please see my question in my comments in the code, and I will appreciate your feedback.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct container {
int *labels[2]; /* two-dimensional array of int */
int **linked_to_container[2]; /* two-dimensional array of pointers to label */
} container;
int get_next_container_index(int current_container_index, int max_index)
{
if (max_index - current_container_index >= 1)
{
return current_container_index + 1;
}
else
return 0; /* elements at two ends are linked */
}
container *allcontainers; /* an array for all containers */
void container_init(int num_containers, int column_num)
{
/* is this right to malloc memory on the array of container when the struct size is still unknown?*/
allcontainers = (container *) malloc(num_containers * sizeof(container));
int i;
for (i = 0; i < num_containers; i++)
{
container *current_container = &allcontainers[i];
current_container->labels[0] = malloc(column_num * sizeof(int));
current_container->labels[1] = malloc(column_num * sizeof(int));
current_container->linked_to_container[0] = malloc(column_num * sizeof(int *));
current_container->linked_to_container[1] = malloc(column_num * sizeof(int *));
int j;
for (j = 0; j < column_num; j++)
{
current_container->labels[0][j] = 0; /* initialize all labels to 0 */
current_container->labels[1][j] = 0;
int next_container = get_next_container_index(i, num_containers - 1); /* max index in all_containers[] is num_containers-1 */
current_container->linked_to_container[0][j] = &(allcontainers[next_container]->labels[0]);
}
}
The line in question seems perfectly fine to me, the size of struct container is well-known, because of its definition. The only size not known is the size of the arrays that the pointers in the struct will eventually point to, but that doesn't affect the size of the pointers themselves and thus also not the struct's size.
The only issue I see is here:
current_container->linked_to_container[0][j] = &(allcontainers[next_container]->labels[0]);
linked_to_container[0][j] is of type int*, but labels[0] is of type int* and therefore &(labels[0]) is of type int**. I am not sure what you try to accomplish here, but you probably need another index to labels[0][...] or & shouldn't be there.
Related
If I had a 2d array with multiple c strings, how would I initialize the array without knowing how many c string will be added into that array.
I have tried to initialize like below but when I try to add a c string I get an error when compiling.
Error : explicit dimensions specification or initializer for an auto or static array.
static Char data[][100];
int main(){
int i;
char word[5];
strcpy(word,"data");
For(i=0; i < rows; i++){
strcpy(data[i],word);
}
}
So the array should hold for example
data[][100]= {"data","data"};
The row value depends on how many rows are retrieved from an sql so my problem is I want to somehow dynamically create the array to fit the size of the rows retrieved from the SQL.
Any help or information would be great.
You can use a pointer to array and reallocation.
#include <stdlib.h> /* for realloc() */
#include <string.h> /* for strcpy() */
int rows = 100; /* for example */
static char (*data)[100] = NULL;
int main(){
int i;
char word[100]; /* allocate array, not a single char */
strcpy(word,"data");
for(i=0; i < rows; i++){
char (*newData)[100] = realloc(data, sizeof(*data) * (i + 1));
if (newData == NULL) { /* allocation error */
free(data);
return 1;
}
data = newData;
strcpy(data[i],word);
}
}
If you don't know how many strings there will be in advance, you either have to set a fixed maximum limit to the static array, or alternatively use dynamic allocation of an array of char pointers.
When using dynamic allocation, you can malloc a "pretty large number" at first, keep track of how many strings there are, and then realloc when you run out of space.
EDIT: pseudo-code example without error handling, free() etc
int main (void)
{
size_t alloc_size = sizeof(char*[100]);
char** data = malloc(alloc_size);
for(size_t i=0; i<rows; i++){
if(i > alloc_size)
{
alloc_size *= 2;
data = realloc(data, alloc_size);
}
size_t str_size = strlen(input)+1;
data[i] = malloc(str_size);
memcpy(data[i], input, str_size);
}
}
I'm new to programming and to C, and I just learned about structs. I'm trying to use them to make an array which can change size as required (so, if the array gets full, it creates a new array double the size, copies the old array into the new one and deletes the old one). All I've done so far is create the struct and the functions for setting it up, and already I'm having problems. The main problem is that, sometimes when I run it it does exactly what I expect it to, which is create the struct, return a pointer to said struct, and then print all elements of the contained array. Other times when I run it, it does nothing at all! I don't get how it can work sometimes, and sometimes not! Obviously i'm doing something really wrong, but I can't work out what. Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int cap;
int used;
void (*cpy) (int *, const int *, int);
//void (*append) (int);
int array[];
} dynArray;
dynArray * new_dynArray(int *, int);
void copy(int *, const int *, int);
int main(void) {
int start_arr[] = {1,2,3,4,5,6};
// create new dynArray, pass start array and number of elemnts
dynArray *arr = new_dynArray(start_arr, \
sizeof(start_arr) / sizeof(start_arr[0]));
// print all elements of dynArray
for (int i=0; i<(arr->used); i++) {
printf("%d, %d\n", arr->array[i], i);
}
free(arr);
return 0;
}
dynArray * new_dynArray(int init_arr[], int size) {
//printf("%d", size);
// if number of elements >= 4 then dynArray size is double, else 8
int init_cap = (size >= 4) ? 2 * size : 8;
// create pointer with enough space for struct and the actual array
dynArray *arr = (dynArray *) malloc(sizeof(dynArray) + init_cap );
arr->cap = init_cap;
arr->used = size;
// assign address of funciton copy to arr->cpy
arr->cpy = copy;
// call the function, to copy init_arr to arr->array
arr->cpy(arr->array, init_arr, size);
return arr;
}
void copy(int dest[], const int src[], int src_size) {
// just copy initial array to new array
int i;
memcpy(dest, src, src_size*sizeof(int));
/*
for (i=0; i<src_size; i++) {
dest[i] = src[i];
printf("%d\n", dest[i]);
}*/
}
So I call init_dynArray, sending a normal array and the number of elements in the array. init_dynArray uses malloc to create space in memory for the struct + the inintal size of the array, set up everything in the struct and copy the array, and then return a pointer to it. I don't get how it can only work some of the time. Hope yuo guys can help, thanks!
The problem in your code is on this line:
dynArray *arr = (dynArray *) malloc(sizeof(dynArray) + init_cap );
You need to multiply init_cap by sizeof(int)
dynArray *arr = (dynArray *) malloc(sizeof(dynArray) + sizeof(int)*init_cap );
You should also use size_t for the init_cap's type.
Note: Storing a pointer to the copying function inside the struct would be useful if your dynamic array consisted of opaque elements that require non-trivial copying. Since copying ints can be accomplished with a simple memcpy, there is no need to store a function pointer in dynArray.
i wasn't able to do a dynamic array of function pointers, i have troubles understanding how to work with a dynamic array of function pointers when having a pointer to the func_cmp pointer.
int(*func_cmp[])(void *,void*);
numElements++;
func_cmp=(func_cmp*)realloc(func_cmp, numElements*sizeof(func_cmp*));
func_cmp[numElements-1]=*func_cmp;
i'm not sure about the realloc line.
Clearest way is to use typedef
#include <stdlib.h>
typedef int (*functype)(void *a, void *);
functype funcs[100]; // static array
functype *moreFuncs; // dynamic array
int main() {
int capacity = 16; // initial capacity
int n = 0; // initial size
moreFuncs = malloc(capacity*sizeof(functype)); // heap dynamic array
// ...
// adding element and need more space
if (n >= capacity) {
capacity *= 2;
moreFuncs = realloc(moreFuncs, capacity);
moreFuncs[n++] = <address of new function>;
}
}
I have a struct called menu_item that looks like:
struct menu_item
{
char name[ITEM_NAME_LEN+1];
};
And in main I declare an array of pointers to the struct (am I right about this part?):
struct menu_item * menu_items[NUM_MENU_ITEMS];
And also in main I'm trying to call:
init_menu(&menu_items[NUM_MENU_ITEMS]);
init_menu function looks like this:
void menu_init(struct menu_item * menu_items[NUM_MENU_ITEMS])
{
/* allocate memory for each element in the array */
menu_items[NUM_MENU_ITEMS] = (struct menu_item *) malloc(sizeof(struct menu_item));
}
However I'm getting a segmentation error, what am I doing wrong? Thanks in advance.
Take a closer look to your function.
void menu_init(struct menu_item * menu_items[NUM_MENU_ITEMS])
{
/* allocate memory for each element in the array */
menu_items[NUM_MENU_ITEMS] = (struct menu_item *) malloc(sizeof(struct menu_item));
}
You need to carry the size of the array in a second parameter in your function. However, NUM_MENU_ITEMS, seems to be a global #define, thus you don't need to carry a second parameter.
Then you are accessing an out of bound cell, menu_items[NUM_MENU_ITEMS]. I assume you know that the indexing starts from 0 and ends at NUM_MENU_ITEMS-1.
In your function, you need, inside a loop, to allocate memory. Moreover, you don't need to cast what malloc returns.
So, for example, you could do something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ITEM_NAME_LEN 15
#define NUM_MENU_ITEMS 3
// Define the struct before main
struct menu_item {
char name[ITEM_NAME_LEN + 1];
};
// Give a synonym. Now struct menu_item is the same with menu_item_t.
// Notice the _t extension, which implies that this is a typedef.
typedef struct menu_item menu_item_t;
/**
* Given a pointer 'p' to an array of pointers
* (of type menu_item_t), allocate memory for
* every cell of the array.
*/
void init_menu(menu_item_t* p[]) {
int i;
for(i = 0; i < NUM_MENU_ITEMS; ++i) {
// for every cell of our array, allocate memory
p[i] = malloc(sizeof(menu_item_t));
// check that allocation for the i-th cell is OK
if(!p[i]) {
printf("Error in allocating %d item!\n\n", i);
return;
}
}
}
/**
* Given a pointer 'p' to an array of pointers
* (of type menu_item_t), de-allocate memory for
* every cell of the array.
*/
void delete_menu(menu_item_t* p[]) {
int i;
for(i = 0; i < NUM_MENU_ITEMS; ++i) {
// free the memory we had allocated for the i-th cell
free(p[i]);
// set the pointer to NULL
p[i] = NULL;
}
}
void fill(menu_item_t* p[]) {
int i;
for(i = 0; i < NUM_MENU_ITEMS; ++i) {
strcpy(p[i]->name, "myitem");
}
}
void print(menu_item_t* p[]) {
int i;
for(i = 0; i < NUM_MENU_ITEMS; ++i) {
printf("%s\n", p[i]->name);
}
}
int main(void) {
// Declare an array of pointers of menu_items_t.
// The size of the array is NUM_MENU_ITEMS
menu_item_t *menu_items[NUM_MENU_ITEMS];
init_menu(menu_items);
fill(menu_items);
print(menu_items);
delete_menu(menu_items);
return 0;
}
When I deal with structs, I always have this example on mind.
You are calling your function as
init_menu(&menu_items[NUM_MENU_ITEMS]);
This does not make sense. Expression &menu_items[NUM_MENU_ITEMS] creates a pointer to element with index NUM_MENU_ITEMS. Such element does not exist. Your array has elements numbered from 0 to NUM_MENU_ITEMS - 1. There's no element with index NUM_MENU_ITEMS.
Expression &menu_items[NUM_MENU_ITEMS] produces a pointer into the uncharted memory past the end of the array. You pass that pointer to the function. Later you are trying to use that pointer as if it were your array. You write into that uncharted memory, which causes a crash.
If you want to pass your array to the function, just pass it. Your function should be called as
init_menu(menu_items);
That's it. There's no need to create any pointers to any elements with strange indices.
Later, inside your function you are again trying to access element NUM_MENU_ITEMS of your array
menu_items[NUM_MENU_ITEMS] = ...
This does not make sense either for the very same reasons.
I have to implement game of life, it is almost complete, the last thing I want to do is to allocate my field dynamical. I'm working under Windows, got no Valgrind and I don't no what's the error in my code. Eclipse shows only that the process is not functional anymore.
Can anyone tell me, what's the problem in my code? Or maybe I don't need a 2 dim. array for game of life field?
struct game_field {
int length;
int **field;
};
static struct game_field *new_game_field(unsigned int l) {
struct game_field *pstField;
pstField = calloc(1, sizeof(struct game_field));
pstField->length = l;
pstField->field = malloc(l * sizeof(int*));
for( int i = 0; i < l; i++ ) {
pstField->field[i] = malloc(l * sizeof(int));
if(NULL == pstField->field[i]) {
printf("No memory for line %d\n",i);
}
}
return pstField;
}
You should think a little bit about the structures and what you are storing.
For the game of life you need to know the state of the cell on the board which is indicated by and integer so your struct should become:
struct game_field {
int length;
int *field;
};
And once you know the dimensions of the field you should allocate it once:
struct game_field *gf = calloc(1, sizeof(struct game_field));
gf->length = <blah>;
gf->field = malloc(gf->length*gf->length*sizeof(int));
This way you have an array of integers that you can use as your board.
The first malloc should be:
pstField->field = malloc(l * sizeof(int*));
Your array is int**, so the first level of allocation is an int*.
Edit: Well, I've tested your code and it does not crash for me. The problem might be somewhere else.
Here's a modification of your code that allocates the field in one block, but still lets you use array brackets for both dimensions:
struct game_field {
int length;
int **field;
};
static struct game_field *new_game_field(unsigned int len)
{
struct game_field *pstField;
pstField = malloc(sizeof(struct game_field));
pstField->length = len;
/* allocate enough space for all the row pointers + the row contents */
pstField->field = malloc((len * sizeof(int *)) + (len * len * sizeof(int)));
/* point the row pointers (at the start of the block) at the row contents
* (further into the block). */
for (int i = 0; i < len; i++)
pstField->field[i] = (int *)(&field[len]) + (i * len);
return pstField;
}
This way you can free the field in one shot:
void free_game_field(struct game_field *gf)
{
free(gf->field);
free(gf);
}
And you can keep the bracket notation to access the elements:
int row7col3 = gf->field[7][3];
Note that what you have (here as well as in your original code) is not exactly a two-dimensional array, but an array of pointers to arrays of integers
(there is a difference, but the arr[x][y] notation can work for either one).