This simple code:
int main()
{
srand(time(NULL));
const int size = rand() % RAND_MAX;
int numbers[size];
int i;
for (i = 0; i < size; i++)
numbers[i] = rand() % RAND_MAX;
for (i = 0; i < size; i++)
printf("numbers[%d]=%d\n", i, numbers[i]);
}
doesn't compile because the size of array isn't const value.
Why does that happen?
How can I fix it?
With ANSI C89 and C90 standard, you have to know the size of the array in advance at compile time. Only in C99 is it allowed for variable sized arrays.
You can either compile it with a c99 compiler or you could allocate memory on the heap:
int *numbers = malloc(size * sizeof(int));
On older compilers defining the length of an array with a variable i.e. not a constant is prohibited.
Use the malloc() function instead:
#include <stdlib.h>
...
const int size = rand() % RAND_MAX;
int *numbers = malloc(sizeof(*numbers)*size);
Related
I find out about Variable Length Array in C99, but it looks like it behave almost the same as malloc + free.
The practical differences I found:
Too big array handling:
unsigned size = 4000000000;
int* ptr = malloc(size); // ptr is 0, program doesn't crash
int array[size]; // segmentation fault, program crashes
Memory leaks: only possible in dynamic array allocation:
int* ptr = malloc(size);
...
if(...)
return;
...
free(ptr);
Life of object and possibility to return from function: dynamically allocated array lives until the memory is frees and can be returned from function which allocated the memory.
Resizing: resizing possible only with pointers to allocated memory.
My questions are:
What are more differences (I'm interested in practical advice)?
What are more problems a programmer can have with both ways of arrays with variable length?
When to choose VLA but when dynamic array allocation?
What is faster: VLA or malloc+free?
Some practical advices:
VLAs are in practice located on the space-limited stack, while malloc() and its friends allocates on the heap, that is likely to allow bigger allocations. Moreveover you have more control on that process, as malloc() could return NULL if it fails. In other words you have to be careful with VLA not-to-blow your stack in runtine.
Not all compilers support VLA, e.g. Visual Studio. Moreover C11 marked them as optional feature and allows not to support them when __STDC_NO_VLA__ macro is defined.
From my experience (numerical programs like finding prime numbers with trial division, Miller-Rabin etc.) I wouldn't say that VLAs are any faster than malloc(). There is some overhead of malloc() call of course, but what seems to be more important is data access efficiency.
Here is some quick & dirty comparison using GNU/Linux x86-64 and GCC compiler. Note that results may vary from platform to another or even compiler's version. You might use as some basic (though very far of being complete) data-access malloc() vs VLA benchmark.
prime-trial-gen.c:
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
bool isprime(int n);
int main(void)
{
FILE *fp = fopen("primes.txt", "w");
assert(fp);
fprintf(fp, "%d\n", 2);
for (int i = 3; i < 10000; i += 2)
if (isprime(i))
fprintf(fp, "%d\n", i);
fclose(fp);
return 0;
}
bool isprime(int n)
{
if (n % 2 == 0)
return false;
for (int i = 3; i * i <= n; i += 2)
if (n % i == 0)
return false;
return true;
}
Compile & run:
$ gcc -std=c99 -pedantic -Wall -W prime-trial-gen.c
$ ./a.out
Then here is second program, that take use of generated "primes dictionary":
prime-trial-test.c:
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
bool isprime(int n, int pre_prime[], int num_pre_primes);
int get_num_lines(FILE *fp);
int main(void)
{
FILE *fp = fopen("primes.txt", "r");
assert(fp);
int num_lines = get_num_lines(fp);
rewind(fp);
#if WANT_VLA
int pre_prime[num_lines];
#else
int *pre_prime = malloc(num_lines * sizeof *pre_prime);
assert(pre_prime);
#endif
for (int i = 0; i < num_lines; i++)
assert(fscanf(fp, "%d", pre_prime + i));
fclose(fp);
/* NOTE: primes.txt holds primes <= 10 000 (10**4), thus we are safe upto 10**8 */
int num_primes = 1; // 2
for (int i = 3; i < 10 * 1000 * 1000; i += 2)
if (isprime(i, pre_prime, num_lines))
++num_primes;
printf("pi(10 000 000) = %d\n", num_primes);
#if !WANT_VLA
free(pre_prime);
#endif
return 0;
}
bool isprime(int n, int pre_prime[], int num_pre_primes)
{
for (int i = 0; i < num_pre_primes && pre_prime[i] * pre_prime[i] <= n; ++i)
if (n % pre_prime[i] == 0)
return false;
return true;
}
int get_num_lines(FILE *fp)
{
int ch, c = 0;
while ((ch = fgetc(fp)) != EOF)
if (ch == '\n')
++c;
return c;
}
Compile & run (malloc version):
$ gcc -O2 -std=c99 -pedantic -Wall -W prime-trial-test.c
$ time ./a.out
pi(10 000 000) = 664579
real 0m1.930s
user 0m1.903s
sys 0m0.013s
Compile & run (VLA version):
$ gcc -DWANT_VLA=1 -O2 -std=c99 -pedantic -Wall -W prime-trial-test.c
ime ./a.out
pi(10 000 000) = 664579
real 0m1.929s
user 0m1.907s
sys 0m0.007s
As you might check π(10**7) is indeed 664,579. Notice that both execution times are almost the same.
One advantage of VLAs is that you can pass variably-dimensioned arrays to functions, which can be handy when dealing with (sanely sized) matrices, for example:
int n = 4;
int m = 5;
int matrix[n][m];
// …code to initialize matrix…
another_func(n, m, matrix);
// No call to free()
where:
void another_func(int n, int m, int matrix[n][m])
{
int sum = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
// …use matrix just like normal…
sum += matrix[i][j];
}
}
// …do something with sum…
}
This is particularly valuable since the alternatives using malloc() without using VLA as well mean that you either have to do subscript calculations manually in the called function, or you have to create a vector of pointers.
Manual subscript calculations
int n = 4;
int m = 5;
int *matrix = malloc(sizeof(*matrix) * n * m);
// …code to initialize matrix…
another_func2(n, m, matrix);
free(matrix);
and:
void another_func2(int n, int m, int *matrix)
{
int sum = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
// …do manual subscripting…
sum += matrix[i * m + j];
}
}
// …do something with sum…
}
Vector of pointers
int n = 4;
int m = 5;
int **matrix = malloc(sizeof(*matrix) * n);
for (int i = 0; i < n; i++)
matrix[i] = malloc(sizeof(matrix[i] * m);
// …code to initialize matrix…
another_func2(n, m, matrix);
for (int i = 0; i < n; i++)
free(matrix[i]);
free(matrix);
and:
void another_func3(int n, int m, int **matrix)
{
int sum = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
// …use matrix 'just' like normal…
// …but there is an extra pointer indirection hidden in this notation…
sum += matrix[i][j];
}
}
// …do something with sum…
}
This form can be optimized to two allocations:
int n = 4;
int m = 5;
int **matrix = malloc(sizeof(*matrix) * n);
int *values = malloc(sizeof(*values) * n * m);
for (int i = 0; i < n; i++)
matrix[i] = &values[i * m];
// …code to initialize matrix…
another_func2(n, m, matrix);
free(values);
free(matrix);
Advantage VLA
There is less bookkeeping work to do when you use VLAs. But if you need to deal with preposterously sized arrays, malloc() still scores. You can use VLAs with malloc() et al if you're careful — see calloc() for an array of array with negative index in C for an example.
question of curiosity
suppose I have:
int main(void)
{
char str[32];
for (i = 0; i < 32; i++)
str[i] = 0;
}
but I want to do it 4x faster
int main(void)
{
char str[32];
for (i = 0; i < 32 / 4; i += 4)
str[i] = (int)0;
}
I expect that the whole array will be filled with zeros.
but array is not filled by zeroes
my questions: why array not filled by zeroes? how to fill array per int blocks? my question is Research for c feature, how to tell the compiler - write blocks of 4 bytes, ie integer registers, it will reduce the number of memory accesses by 4 times, on x64 processors reduce 8 times
thanks for all, follows work well:
int main(int argc, char *argv[])
{
char str[32];
int i;
for (i = 0; i < 32; i++)
str[i] = 12;
for (i = 0; i < 32 / sizeof(int); i++)
((int *) str)[i] = 0;
printf("%d\n", i);
for (i = 0; i < 32; i++)
printf("%d\n", str[i]);
return 0;
}
The correct and fastest way is to initialize the array to zero
char str[32] = { 0 } ;
If you want to set the array to zero afterwards, then use memset and enable compiler optimization and intrinsic functions, and the compiler will figure out the fastest way to zero the array.
memset( str , 0 , sizeof( str ) ) ;
As pointed out by #user2501, initializing to {0} or using memset is the fastest and correct way.
If you are tempted to use something like ((int *)str)[i] = 0, do not, this can result in unaligned access.
As an alternative to memset, in C99 (and assuming that int is 4 bytes) you can use the type punning feature of unions:
#include <stdio.h>
typedef union {
char as_string[32];
int as_int[8];
} foo;
int main(void)
{
foo x;
int i;
for (i = 0; i < 8; i++)
x.as_int[i] = 0;
for (i = 0; i < 32; i++)
printf("%d", x.as_string[i]);
printf("\n");
return 0;
}
Output:
00000000000000000000000000000000
Seems that you are forced to use pointers and casts, this version uses the heap in order to allocate str on an address properly aligned for int:
#include <stdio.h>
#include <stdlib.h> /* malloc, free */
#include <stdint.h> /* intptr_t (pointer arithmetic using modulo division) */
#define MAX 32
int main(void)
{
size_t i, align;
char *ptr, *str;
align = __alignof__(int);
ptr = malloc(MAX + align); /* MAX + max align distance */
str = ptr + align - (intptr_t)ptr % align; /* now str is properly aligned */
for (i = 0; i < MAX / sizeof(int); i++)
((int *)str)[i] = 0;
for (i = 0; i < MAX; i++)
printf("%d\n", str[i]);
free(ptr);
return 0;
}
Note that __alignof__ is a gcc extension, change to __alignof if you are under Visual Studio or _Alignof if you are comfortable with C11.
You have to cast the pointer as the int, not the value:
int main(void)
{
char str[32];
for (i = 0; i < 32/sizeof(int); i++)
((int *) str)[i] = 0xAABBCCDD; //Be careful of Endianness
}
Alternatively:
int i;
union block_fill
{
char arr[24];
int iarr[6];
};
union block_fill block_arr;
for(i=0; i<6; i++)
block_arr.iarr[i] = 0x11223344;
for(i=0; i<24; i++)
printf("%x", block_arr.arr[i]);
I want to fill big array with rand() function, when I define my array by int h_in[N],the program crash in vs 2010,to my surprise, when I copy it to the online complier ideone a linkand everything is ok.Finally I define array by h_in = (int *)malloc(N * sizeof(int)) in VS 2010,the program works.I can't figure out that and hope somebody point out my error.
#include <stdio.h>
#include <stdlib.h>
const int N = 1024 * 1024;
int main()
{
//int *h_in = (int *)malloc(N * sizeof(int));
int h_in[N];
float sum = 0.0f;
srand(1);
for(unsigned int i = 0; i < N; i++) {
h_in[i] = (rand() & 0xFF);
}
return 0;
}
int h_in[N];
is allocated on the stack.
int * h_in = malloc(N * sizeof(int));
is allocated on the heap. [BTW: don't cast the result of malloc()]
The default stack size is 1MB, so you should use a linker option to increase it:
/F (Set Stack Size)
I have an integer variable x that I need to use to make two 2D arrays but I get an error of "cannot allocate an array of constant size 0". After doing some research I apparently need to use malloc but I have no idea how to apply it to my currently situation.
My two arrays I need:
int firMat[x][5];
int secMat[5][x];
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int x = 2;
int **firMat;//int firMat[x][5];
int **secMat;//secMat[5][x];
int i;
firMat = malloc(x * sizeof(int*));
for(i = 0; i< x; ++i)
firMat[i] = malloc(5 * sizeof(int));
secMat = malloc(5 * sizeof(int*));
for(i = 0; i< 5; ++i)
secMat[i] = malloc(x * sizeof(int));
//do stuff E.g. fir[2][1] = 21;
//release E.g.
//for(i = 0; i< x; ++i)
// free(firMat[i]);
//free(firMat);
return 0;
}
If you're using C99, this will work. It will create a "variable-length array", sadly VLAs have been reduced to "optional" in C11.
To use malloc for this, typically I'd abandon the double-array notation, and treat the memory as a flat one-dimensional array, then array[i][j] becomes ptr[ i*cols + j ].
Try to initialize x like in the example below
#define x 2 //outside the function
and then use x like this
int firMat[x][5];
int secMat[5][x];
I am trying to dynamically allocate a 2D array, put some values, and print output. However it seems that I am making mistake in getting input to program in atoi() function.
Basically when we assign a static 2D array, we declare it as say int a [3][3]. So 3*3 units if int, that much memory gets allocated. Is same thing holds for allocating dynamic array as well?
Here is my code:
#include<stdio.h>
#include<stdlib.h>
int main(int arg,char* argv)
{
int rows = atoi(argv[1]);
int col = atoi(argv[2]);
int rows =3;
int col=3;
int i,j;
int (*arr)[col] = malloc(sizeof (*arr)*rows);
int *ptr = &(arr[0][0]);
int ct=1;
for (i=0;i<rows;i++)
{
for(j=0;j<col;j++)
{
arr[i][j]=ct;
ct++;
}
}
printf("printing array \n");
for (i=0;i<rows;i++)
{
for(j=0;j<col;j++)
{
printf("%d \t",arr[i][j]);
}
printf("\n");
}
free(arr);
return (0);
}
Program crashes in runtime. Can someone comment?
Try to change the third line to:
int main(int arg,char **argv)
The common method to use dynamic matrices is to use a pointer to pointer to something, and then allocate both "dimensions" dynamically:
int **arr = malloc(sizeof(*arr) * rows);
for (int i = 0; i < rows; ++i)
arr[i] = malloc(sizeof(**arr) * col);
Remember that to free the matrix, you have to free all "rows" in a loop first.
int rows = atoi(argv[1]);
int col = atoi(argv[2]);
int rows =3;
int col=3;
int i,j;
You are defining rows and col twice.... that would never work!
With traditional C, you can only have the array[][] structure for multiple dimension arrays work with compile time constant values. Otherwise, the pointer arithmetic is not correct.
For dynamically sized multi dimensional arrays (those where rows and cols are determined at runtime), you need to do additional pointer arithmetic of this type:
int *a;
int rows=3;
int cols=4;
a = malloc(rows * cols * sizeof(int));
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
a[i*rows + j] = 1;
free(a);
Alternatively, you can use double indirection and have an array of pointers each pointing to a one dimensional array.
If you are using GCC or any C99 compiler, dynamic calculation of multiple dimension arrays is simplified by using variable length arrays:
// This is your code -- simplified
#include <stdio.h>
int main(int argc, const char * argv[])
{
int rows = atoi(argv[1]);
int col = atoi(argv[2]);
// you can have a rough test of sanity by comparing rows * col * sizeof(int) < SIZE_MAX
int arr[rows][col]; // note the dynamic sizing of arr here
int ct=1;
for (int i=0;i<rows;i++)
for(int j=0;j<col;j++)
arr[i][j]=ct++;
printf("printing array \n");
for (int i=0;i<rows;i++)
{
for(int j=0;j<col;j++)
{
printf("%d \t",arr[i][j]);
}
printf("\n");
}
return 0;
} // arr automatically freed off the stack
With a variable length array ("VLA"), dynamic multiple dimension arrays in C become far easier.
Compare:
void f1(int m, int n)
{
// dynamically declare an array of floats n by m size and fill with 1.0
float *a;
a = malloc(m * n * sizeof(float));
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
a[i*n + j] = 1.0;
free(a);
}
With VLA you can write to do the same:
void f2(int m, int n)
{
// Use VLA to dynamically declare an array of floats n by m size and fill with 1.0
float a[m][n];
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
a[i][j] = 1.0;
}
Be aware that unlike malloc / free VLA's handling of requesting a size larger than what is available on the stack is not as easily detected as using malloc and testing for a NULL pointer. VLA's are essentially automatic variables and have similar ease and restrictions.
VLA's are better used for smaller data structures that would be on the stack anyway. Use the more robust malloc / free with appropriate detection of failure for larger data structures.
If you are not using a fairly recent vintage C compiler that supports C99 -- time to get one.