Here's what I'm trying to do:
I need a global array with a length that is dependent on a variable (NumOfRequests). That variable is set within a function. I don't think it's possible to declare a global array within a function as I tried to do in the following code:
static uint8 NumOfRequests;
typedef struct
{
uint16 IndexToRequest;
GdXRequestData_ts RequestData;
bool RequestSent;
} GdRequests;
static void SetupRequestStructures( void )
{
uint8 i;
for( i = 0; EepromData_ps.GD_Indices[i] != 0xFFFF; i++ )
{
NumOfRequests = i + 1;
}
GdRequests Requests[NumOfRequests];
for( i = 0; i < NumOfRequests; i++ )
{
Requests[i].IndexToRequest = EepromData_ps.GD_Indices[i];
}
}
It's not possible to declare an array and later decide what length it should be or change its length, as far as I know.
So does anyone know another solution for how to declare a global array with a length based on a variable that is set within a function?
Any feedback is appreciated. If you upvote or downvote, tell me why so I can improve with future questions.
You can use dynamic memory allocation to perform this task. Look at malloc and free. Here's a simple example of dynamic memory allocation on a global array of structs:
#include <stdio.h>
#include <stdlib.h>
typedef struct _MyStruct
{
int a;
int b;
} MyStruct;
MyStruct *g_Array = NULL;
void populatearray(MyStruct *array, int length)
{
int i;
for(i = 0; i < length; i++)
{
array[i].a = i;
array[i].b = i;
}
}
void printstructs(MyStruct *array, int length)
{
int i;
for(i = 0; i < length; i++)
{
printf("array[%d].a = %d\narray[%d].b = %d\n\n", i, array[i].a, i, array[i].b);
}
}
int main()
{
g_Array = malloc(50 * sizeof(MyStruct));
if(!g_Array)
{
puts("Malloc failed");
return 0;
}
populatearray(g_Array, 50);
printstructs(g_Array, 50);
free(g_Array);
return 0;
}
Related
I am trying to make a program that first creates an array in another function, returns it and then calls another function that shuffles the contents of the array and returns it. However I am struggling to do this in C since I do not quite understand the array pointer system that has to be used here.
So far my code doesnt return the values 1-20 from makeArray() but instead returns an array full of 0s and I have a feeling it has to do with the c's array pointer system.
Any help would greatly be appreciated! Thank you in advance
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int arrShuffle();
int arrShuffle(int * arr) {
int arr[21];
// shuffle array
for(int j=0; j<20; j++) {
int randInd = (rand() % 20) + 1;
int temp = arr[j];
arr[j] = arr[randInd];
arr[randInd] = temp;
}
return arr;
}
int makeArray() {
int arr[21];
// make array of 1-20
for(int i=0; i < 20; i++) {
arr[i] = i + 1;
}
return arr;
}
void main() {
int *orgArr;
int *modArr;
srand(time(NULL));
orgArr = makeArray();
for(int i=0; i < 20; i++) {
printf("OrgArr: %d\n", orgArr);
}
modArr = arrShuffle(orgArr);
}
You cannot use variables with automatic storage (aka local ones). You must allocate the array so the memory remains valid after the function ends:
int* makeArray() {
int *arr = calloc(21, sizeof *a);
// make array of 1-20
for(int i=0; i < 20; i++) {
arr[i] = i + 1;
}
return arr;
}
Remember to release the array when it is no longer used:
int main() {
int *orgArr;
...
orgArr = makeArray();
...
free(orgArr);
}
As tstanisl pointed out in their answer, a possible solution is to use dynamic memory allocation. My answer, instead, will give you yet another solution: using an array passed by the caller.
NOTE: both solutions are valid and their usefulness depends on the specific needs of your program. There's no "right" universal solution.
void makeArray(int arr[], size_t len) {
for (size_t i = 0; i < len; i += 1) {
arr[i] = (int) (i + 1);
}
}
void cloneAndModifyArray(const int orig[], int new[], size_t len) {
for (size_t i = 0; i < len; i += 1) {
new[i] = orig[i] * 2; // or some other modification
}
}
And you use it like this:
#define ARR_LEN (100)
int main(void) {
int arr[ARR_LEN];
makeArray(arr, ARR_LEN);
int modified_arr[ARR_LEN];
cloneAndModifyArray(arr, modified_arr, ARR_LEN);
return 0;
}
I'm trying to create a function that creates a variable sized 2D funct array. I'm using the following code, which seems to work just fine on its own:
typedef struct
{
//Starter Properties
int TypeB;
int TypeF;
int TypeW;
//Randomized Properties
int RandB;
int RandF;
int RandW;
//Derived Properties
int Speed;
} MapTileData;
MapTileData **Map;
int i, x=5, y=5;
//Allocate Initial Space
Map = (MapTileData**)calloc(x, sizeof(MapTileData));
for(i = 0; i < x; i++)
{
Map[i] = (MapTileData*)calloc(y, sizeof(MapTileData));
}
So the above code creates a 2D struct array. My attempts to move the code to a function have been less successful, giving segmentation faults when trying to print the array:
void CreateMap(MapTileData **Map, int xSize, int ySize)
{
//Variables
int i;
//Allocate Initial Space
Map = (MapTileData**)calloc(xSize, sizeof(MapTileData));
for(i = 0; i < xSize; i++)
{
Map[i] = (MapTileData*)calloc(ySize, sizeof(MapTileData));
}
}
Used in the code:
MapTileData **MapTile;
CreateMap(MapTile,5,5);
Any and all help is greatly appreciated!
Function arguments are passed by value in C and modifying arguments in callee won't affect caller's local variables.
Use pointers to modify caller's local variables.
void CreateMap(MapTileData ***Map, int xSize, int ySize)
{
//Variables
int i;
//Allocate Initial Space
*Map = calloc(xSize, sizeof(MapTileData));
for(i = 0; i < xSize; i++)
{
(*Map)[i] = calloc(ySize, sizeof(MapTileData));
}
}
Usage in the code:
MapTileData **MapTile;
CreateMap(&MapTile,5,5);
Alternate way: Pass the allocated array via the return value.
MapTileData **CreateMap(int xSize, int ySize)
{
//Variables
MapTileData **Map;
int i;
//Allocate Initial Space
Map = calloc(xSize, sizeof(MapTileData));
for(i = 0; i < xSize; i++)
{
Map[i] = calloc(ySize, sizeof(MapTileData));
}
//Return the value
return Map;
}
Usage in the code:
MapTileData **MapTile;
Maptile = CreateMap(5,5);
Also note that they say you shouldn't cast the result of malloc() and its family in C.
I'm trying to create a function that creates a variable sized 2D funct array. I'm using the following code, which seems to work just fine on its own:
typedef struct
{
//Starter Properties
int TypeB;
int TypeF;
int TypeW;
//Randomized Properties
int RandB;
int RandF;
int RandW;
//Derived Properties
int Speed;
} MapTileData;
MapTileData **Map;
int i, x=5, y=5;
//Allocate Initial Space
Map = (MapTileData**)calloc(x, sizeof(MapTileData));
for(i = 0; i < x; i++)
{
Map[i] = (MapTileData*)calloc(y, sizeof(MapTileData));
}
So the above code creates a 2D struct array. My attempts to move the code to a function have been less successful, giving segmentation faults when trying to print the array:
void CreateMap(MapTileData **Map, int xSize, int ySize)
{
//Variables
int i;
//Allocate Initial Space
Map = (MapTileData**)calloc(xSize, sizeof(MapTileData));
for(i = 0; i < xSize; i++)
{
Map[i] = (MapTileData*)calloc(ySize, sizeof(MapTileData));
}
}
Used in the code:
MapTileData **MapTile;
CreateMap(MapTile,5,5);
Any and all help is greatly appreciated!
Function arguments are passed by value in C and modifying arguments in callee won't affect caller's local variables.
Use pointers to modify caller's local variables.
void CreateMap(MapTileData ***Map, int xSize, int ySize)
{
//Variables
int i;
//Allocate Initial Space
*Map = calloc(xSize, sizeof(MapTileData));
for(i = 0; i < xSize; i++)
{
(*Map)[i] = calloc(ySize, sizeof(MapTileData));
}
}
Usage in the code:
MapTileData **MapTile;
CreateMap(&MapTile,5,5);
Alternate way: Pass the allocated array via the return value.
MapTileData **CreateMap(int xSize, int ySize)
{
//Variables
MapTileData **Map;
int i;
//Allocate Initial Space
Map = calloc(xSize, sizeof(MapTileData));
for(i = 0; i < xSize; i++)
{
Map[i] = calloc(ySize, sizeof(MapTileData));
}
//Return the value
return Map;
}
Usage in the code:
MapTileData **MapTile;
Maptile = CreateMap(5,5);
Also note that they say you shouldn't cast the result of malloc() and its family in C.
I have defined these 2 structs:
#define MAP_SIZE 5
typedef struct battle_cell {
int status_a;
int status_b;
int ship_a;
int ship_b;
} battle_cell;
struct battlemap {
battle_cell cell[MAP_SIZE][MAP_SIZE];
int progress_a;
int progress_b;
};
After the initalization of the map and all the other variables with zeros:
for (i = 0; i < MAP_SIZE; i++) {
for (j = 0; j < MAP_SIZE; j++) {
map->cell[i][j].status_a = 0;
map->cell[i][j].status_b = 0;
map->cell[i][j].ship_a = 0;
map->cell[i][j].ship_b = 0;
}
}
map->progress_a = 0;
map->progress_b = 0;
There is a point that I have to check the ship_a and ship_b values that live in each cell, something like that (the logic is a bit more complex than this iteration):
for (i = posXB; i < posXB + SHIP_SIZE; i++) {
map->cell[posYB][i].ship_b = 1;
}
I need to do exactly the same for the ship_a variable. So, I have to duplicate quite a big chunk of code because I am not able to find a way to get the field within the struct dynamically. For example, I could define a function:
void cell_iteration (battlemap *map, int pos, int pos_y, int ship_size, /* field_parameter/pointer */) {
int i;
for (i = pos; i < pos + ship_size; i++) {
map->cell[pos_y][i].ship_b = 1; // use the field_parameter/pointer instead of ship_b
}
}
Is there an elegant way to do something like that?
UPDATE
Just a clarification. The structs can definitely be simplified, but this is not my question. I 've just tried to create an example :)
Instead if ship_a and ship_b int the first struct, you can declare int ship[2] an array of 2 int.
I find this hard to explain but I'll do my best. I am passing an array to a function. I want to be able to grab the pointer of the array in the function and put the values of the array back into an array in the function.
If that doesn't make sense maybe this code will give you an idea of what I'm trying to attempt.
#define LENGTH 3
void FIR(short *filter) {
short temp[LENGTH] = {*filter, *(filter+1), *(filter+2)};
}
int main() {
short filter[LENGTH] = {1,2,5};
FIR(filter);
}
This code works but is quite ridiculous if the filter length is long. How could I do this for any length of filter array? Keep in my mind, I'm trying to preserve efficiency.
Use a loop, *(filter+x) is equivalent to filter[x]
#include <stdio.h>
#define LENGTH 3
void FIR(short *filter) {
short temp[LENGTH];
int i;
for(i = 0; i < LENGTH; ++i){
temp[i] = filter[i];
}
}
int main() {
short filter[LENGTH] = {1,2,5};
FIR(filter);
int i;
for(i = 0; i < LENGTH; ++i){
printf("%d ", filter[i]);
}
}
You can make your code look good by using loops or just use memcpy() to copy the whole array.
void FIR(short *filter)
{
short temp[LENGTH];
int i=0;
for(i=0;i<LENGTH;i++)
temp[i] = filter[i];
// or memcpy(temp,filter,sizeof(short) * LENGTH);
}
Since you talk about efficiency then go for the latter approach i.e. memcpy()
The most efficient approach is likely a memcpy. Since you know the type and size of the array.
#define LENGTH 3
void FIR(short *filter) {
short temp[LENGTH];
memcpy(temp, filter, sizeof(short)*LENGTH)
}
You could use memcpy(), or you could initialize your local array in a loop. For example,
void FIR(short *filter) {
short temp[LENGTH];
memcpy(temp, filter, LENGTH * sizeof(short));
}
or
void FIR(short *filter) {
short temp[LENGTH];
int i;
for (i = 0; i < LENGTH; i += 1) {
temp[i] = filter[i];
}
}
Other than memcopy(), one way is by using pointers:
void FIR(short *filter)
{
short temp[LENGTH], *tempP;
int i = 0;
tempP = temp;
while(LENGTH > i++) *tempP++ = *filter++;
}
If you want the length to be variable then use this
#include <stdio.h>
void FIR(short *filter, int length) {
short *temp = new short[length];
int i;
for(i = 0; i < length; ++i){
temp[i] = filter[i];
}
}
int main() {
short filter[3] = {1,2,5};
FIR(filter, 3);
int i;
for(i = 0; i < 3; ++i){
printf("%d ", filter[i]);
}
}