Not using C that often, I came across a possibly simple problem. I have several functions, that need access to a global array-variable g. But the actual size of this variable has to be defined in an init()-function. The size depends on some other stuff, so g has to be declared somehow with a dynamic size. I read about malloc and other functions, but I am not sure how to use them properly.
Example:
double g[dynamic]; // size is not known yet
int n;
void init()
{
// calculate "n" for array size
n = ...
// declare and initialze g with a size "n"
}
void dostuff()
{
for (int i = 0; i < n; i++)
work(g[i]);
}
How should I solve this?
You cannot use an array. You must use a pointer.
double *global_array; // size is not known yet
size_t nglobal_array; // may be helpful to have the size
void init(void)
{
// calculate "nglobal_array" for array size
nglobal_array = 42;
// declare and initialze global_array with a size "nglobal_array"
global_array = malloc(nglobal_array * sizeof *global_array);
if (global_array == NULL) {
fprintf(stderr, "Error allocating resources.\nProgram aborted.\n");
exit(EXIT_FAILURE);
}
}
void dostuff()
{
for (int i = 0; i < nglobal_array; i++)
work(global_array[i]);
}
Don't forget to free(global_array) when you no longer need it.
Complete usage would then be something like this
#include <stdlib.h>
// includes
// declarations & definitions as above
int main(void) {
init();
dostuff();
free(global_array);
}
What you want to achieve is not possible in C.
A global array must have a fixed size at compile, or at least at link time.
You can declare the array without a specified size:
extern double g[];
But it must be defined somewhere with an actual size, computed from a constant expression at the definition place, and the size cannot be determined from the above declaration, so it must be passed some other way to the functions that will use the array: either implicitly, with a special value signifying the end of the array (like '\0' for char strings) or explicitly via a separate variable as you posted. Note however that n and g are very poor name choices for global variables as they are likely to clash with local variable names and convey no meaning to the reader.
If the size is not known until run time, you should define a pointer instead of an array and also define a separate variable with the length of the array that will be allocated by the initialization function.
double *g;
size_t g_length;
No. C doesn't do that. Arrays declared in global scope have fixed space allocated for them in your binary(.EXE files on Windows and ELF executables on Linux). If you want an array of dynamic size, you need to dynamically allocate it.
Example is here:
#include <stdlib.h>
#define ARRAY_SIZE 100
typedef char T; //your type here
T* array;
void init() {
array = malloc(sizeof(T) * ARRAY_SIZE); //array filled with garbage values
//array = calloc(ARRAY_SIZE, sizeof(T)); //array filled with 0x00
}
void finish() {
free(array); // DO NOT ACCESS ARRAY AFTER THIS CALL!
}
int main() {
init();
array[6] = 63; //access array as normal
finish();
//array[41] = 23; //will most likely crash due to a segmentation fault, also called an access violation on Windoez
}
Related
I have an array that I want to have in global scope. Its size however is determined during runtime, so I can't initialize it where I define it.
How can I declare it in global scope and assign its size in the main function?
#include <stdlib.h> // for malloc
int *globalarray;
int main()
{
...
globalarray = malloc(thesizeyouwant * sizeof(*globalarray));
...
globalarray[0] = foo;
...
free(globalarray);
}
After your comment I guess there is no way of having the array on the stack, I wanted to show you that the pointer and the pointed object can have any storage. If the C implementation support Variable Length Array, you can make your global pointer point to a VLA:
int *glob_array;
int main() {
...
// obtain the size of the array in sz:
size_t sz;
sz = ...
int arr[sz];
glob_arr = arr; // a global pointer to a VLA
...
}
As arr is defined in main (and not in a sub block) it will only reach its end of life when the program will end. Yet it has automatic storage, meaning that for most implementation it will reside in the stack.
Disclaimer: the actual allocation is an implementation detail, and the compiler could allocate it in a heap if it wants to.
I want to dynamically define and allocate pointers:
#include<stdio.h>
#define def_var(type,name,i) type name##i
#define var(name,i) name##i
void main(){
int i;
for (i=0;i<10;i++){
def_var(float,*ww,i)=NULL;
}
for (i=0;i<10;i++){
var(ww,i)=(float *)malloc(100);
}
}
But when I compile it, lots of error come up. Can anybody help fix it?
You can't do what you're trying to do. Preprocessor macros are expanded at compile time, they can't depend on run-time variable values. So
def_var(float,*ww,i)=NULL;
is expanded into
float *wwi = NULL;
It doesn't, and can't, replace i with the value of the variable, it just performs text substitution.
Also, variable declarations have block scope, so any variables declared inside the for loop go away when the loop finishes.
Just declare an array of pointers.
float *ww[10];
for (int i = 0; i < 10; i++) {
ww[i] = malloc(100 * sizeof(float *));
}
If ww is supposed to represent 10 arrays of 100 floats each (known numbers at compile time), then just use a multi-dimensional array:
float ww[10][100];
and index accordingly when used (eg: ww[7][93] = 6;).
If 'ww' must contain dynamically allocated pointers as you say, then use (where each element is a pointer to an array of 100 floats)
float (*ww[10]) [100];
for (i=0;i<10;i++){
ww[i]=malloc(sizeof(float)*100);
}
and index accordingly when used (eg: (*(ww[7]))[93] = 6; or ww[7]->[93] = 6;).
Remember to free each when done.
for (i=0;i<10;i++){
free(ww[i]);
}
Caution: Remember malloc will not intialize the newly allocated memory - that is up to you! Strongly recommended to use calloc instead to zero-out the memory instead, so it is in a known state.
I'm trying to store 4 arrays in an array, and for some reason, the last value keeps overriding the previous three values. For example, if 123; 456; 789; 987 were inputted into the code below, ipadr[0] - ipadr[4] would all only store 123. I've tested to make sure that numConvert() is working, and within numConvert, 4 different arrays of ints are returned, but only numConvert(d) is the ipadr array (stored 4 times).
Also, is my syntax / code correct in order for this function to return ipadr as an array of arrays (int**)? Why do you need to make it static int* when initializing the array?
I'm new to C and this has been really frustrating me. Any help would be incredibly appreciated. Thank you in advance!!
int** ipConvert(int a, int b, int c, int d){
static int* ipadr[4];
ipadr[0]=numConvert(a);
ipadr[1]=numConvert(b);
ipadr[2]=numConvert(c);
ipadr[3]=numConvert(d);
return ipadr;
}
numConvert code:
int* numConvert(int dec) {
static int hold[8];
...
return hold;
}
The hold array is indeed overwritten after each call to numConvert, because it is a static area of 8 int.
Better use dynamic allocation with malloc, and have that function allocate 8 ints.
int* numConvert(int dec) {
int *hold = (int *)malloc(sizeof(int) * 8); // C++ need cast!
int x = dec;
for(int y=7;y>=0;y--){
if(x%2==0 || x==0){
hold[y]=0;
}
else{
hold[y]=1;
}
x=x/2;
}
printf("\ntest loop: ");
for(int i=0;i<8;i++){
printf("%i", hold[i]);
}
printf("\n");
return hold;
}
then the returned values will have to be freed, after you don't need them anymore.
As for static, this answer explains it in details.
Every time you write something in hold then return it, you basically overwrite the previous value. There is single instance of hold not multiple as you may be thinking.
static keyword you have used without knowing the full functionality. It is not the same as automatic storage duration.
int* numConvert(int dec) {
int *hold = malloc(sizeof *hold *8);
if( hold == NULL){
fprintf(stderr,"Error in malloc");
exit(1);
}
int x = dec;
....
....
return hold;
}
Free the dynamically allocated memory when you are done working with it.
What have we done here?
Dynamically allocated memory has lifetime beyond the scope of the function. So just like the static one it stays alive. But with contrary to the static variable each time a new chunk of memory is allocated. And for that we are not overwriting anything, which was the primary problem in your case.
One thing more..
hold is of automatic storage duration meaning every time we exit the function the hold is deallocated and then again when we call it we get to have a local variable named hold. So in each we get different instance. And that's why we return the address contained in hold. This memory whose address hold contains has lifetime beyond the scope of the function. So it stays unlike the local variable hold and we store this address in other function.
Declare your hold variable as instance variable rather then static variable like
int* numConvert(int dec) {
int hold[8];
A portion of my C code is shown below.
int data[10]={1,3,6,8,1,7,9,1,1,1};
b=10;
int out[b];
process(data, &b, out);
alpha (out, b);
data and out are int arrays. The function process takes the array data whose length is pointed by b (=10) and performs mathematical operation and then returns an array out whose length is then again returned by b (unknown and hence required to be dynamically allocated). Then the array out is sent with function alpha. Right now the function alpha always sends out[10] since b has been declared as 10 in second line of code. How can I allocate array out dynamically so that it contains only valid data returned after function process.
You need to know the difference between dynamic and static allocations.
There are 3 alternatives:
Static allocation:
You need to know in advance the array length. It must be a number and not a variable:
int out[10];
Array is static and is only locally scoped. So if you do:
function do_something()
{
int out[10];
}
you can't use the out array outside the function. But you can define out
outside and send it like this:
function do_something(int* out)
{
// do things
}
...
{
int out[10];
do_something(out);
}
Automatic allocation
When you do
int b = 100;
int out[b];
(which won't compile on gcc without the -std=c99 or -std=c11 flag), you get an automatic variable, which is very convenient if you don't use out out of scope, but can be a bit dangerous. The resulting array is generated in the Stack, and is destroyed when it goes out of scope (which is why it can get you into trouble if you use it freely). See
https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Variable-Length.html
We suggest you use:
Dynamic allocation
Where the array is generated on the Heap and you are responsible to clean it up when you're done with it. The down side is you need to clean it up yourself. The up side is you can use pass it around and use it anywhere.
int b=100;
int* out = (int*) malloc(b * sizeof(int));
// do things with out
free(out);
VERY IMPORTANT:
Do not change the value of the pointer out. If you do, then you won't free the right amount of memory. A nice thing to do is to copy the pointer, and use the copied address for free:
int b=100;
int* out = (int*) malloc(b * sizeof(int));
int* out_copy = out;
// do things with out. don't touch out_copy
free(out_copy);
int *out;
out=(int *) malloc(sizeof(int) * 10);
This will produce array out of integer type with size 10.
You need out to be a pointer - not an array - and you need to pass a pointer to out to the function, just like you do with b.
Example:
void f(int **a, int *size)
{
*a = malloc(23 * sizeof(**a));
*size = 23;
}
/* ... */
int *p = NULL;
int b = 0;
f(&p, &b);
/* 'p' has been allocated and 'b' has its size. */
I need to store an array of point (x,y). I read the points from a file, and the number of points are not constant, but i can get it at the first line of the file. So i write a procedure load() to loading the points from the file and store them in a global array. It doesn't work.
My code:
int *array[][]; // this is a pointer to a 2-dimensional array??
void load(){
..
int tempArray[2][n]; //n is the first line of the file
..
array = tempArray;
}
You're trying to return a pointer to memory that is local to the function that defines the variable. Once that function stops running ("goes out of scope"), that memory is re-used for something else, so it's illegal to try and reference it later.
You should look into dynamic allocation, and have the loading function allocate the needed memory and return it.
The function prototype could be:
int * read_points(const char *filename, size_t *num_points);
Where filename is of course the name of the file to open, num_points is set to the number of points found, and the returned value is a pointer to an array holding x and y values, interleaved. So this would print the coordinates of the first point loaded:
size_t num_points;
int *points;
if((points = load_points("my_points.txt", &num_points)) != NULL)
{
if(num_points > 0)
printf("the first point is (%d,%d)\n", points[0], points[1]);
free(points);
}
This declaration of yours does not work:
int *array[][]; // this is a pointer to a 2-dimensional array??
First, it is trying to declare a 2D array of int *. Second, when you declare or define an array, all dimensions except the first must be specified (sized).
int (*array)[][2]; // This is a pointer to a 2D array of unknown size
This could now be used in a major variant of your function. It's a variant because I misread your question at first.
void load(void)
{
...
int tempArray[n][2]; // Note the reversed order of dimensions!
...
array = &tempArray;
...there must be some code here calling functions that use array...
array = 0;
}
Note that the assignment requires the & on the array name. In the other functions, you'd need to write:
n = (*array)[i][j];
Note, too, that assigning the address of a local array to a global variable is dangerous. Once the function load() returns, the storage space for tempArray is no longer valid. Hence, the only safe way to make the assignment is to then call functions that reference the global variable, and then to reset the global before exiting the function. (Or, at least, recognize that the value is invalid. But setting it to zero - a null pointer - will more nearly ensure that the program crashes, rather than just accessing random memory.
Alternatively, you need to get into dynamic memory allocation for the array.
Your question actually is wanting to make a global pointer to a VLA, variable-length array, where the variable dimension is not the first:
int tempArray[2][n]; // Note the reversed order of dimensions!
You simply can't create a global pointer to such an array.
So, there are multiple problems:
Notation for pointers to arrays
Initializing pointers to arrays
Assigning global pointers to local variables
You can't have global pointers to multi-dimensional VLAs where the variable lengths are not in the first dimension.
You should minimize the use of globals.
A more elegant version might go like this:
typedef struct point_ { int x; int y; } point;
point * create_array(size_t n)
{
return calloc(n, sizeof(point));
}
void free_array(point * p)
{
free(p);
}
int main()
{
size_t len = read_number_from_file();
point * data = create_array(len);
if (!data) { panic_and_die(); }
for (size_t i = 0; i != len; ++i)
{
/* manipulate data[i].x and data[i].y */
}
free_array(data);
data = 0; /* some people like to do this */
}
You are trying to assign an array but in C arrays cannot be assigned.
Use memcpy to copy one array to another array. Arrays elements in C are guaranteed to be contiguous.
int bla[N][M] = {0};
int blop[N][M];
/* Copy bla array to blop */
memcpy(blop, bla, sizeof blop);