Use Initialization List in C after declaration - c

I am learning C and some things confuse me and the books I have read didn't really help in clarifying the problem I have.
So here is the code I have:
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE 5
// gcc -std=c99 stackoverflow-example.c
int main () {
// declare variable array1
int array1[ARRAY_SIZE];
// declare and init variable array2
int array2[ARRAY_SIZE] = {}; // for integers, the default value is 0
// not initialized
for (int i = 0; i < ARRAY_SIZE; i++) {
// can be anything, not guaranteed to be 0
printf("array1[%d]: %d\n", i, array1[i]);
}
// initialized with initialization list
for (int i = 0; i < ARRAY_SIZE; i++) {
// element == 0
printf("array2[%d]: %d\n", i, array2[i]);
}
// This is the part that confuses me.
// array1 = {}; // error: expected expression before ‘{’ token
// array1[] = {}; // same error
return EXIT_SUCCESS;
}
Is there a handy way to initialize this array after its declaration? Or the only way to set every element in array1 is with a for loop, e.g.:
for (int i = 0; i < ARRAY_SIZE; i++)
array1[i] = 0;
// initialized with a for loop
for (int i = 0; i < ARRAY_SIZE; i++)
// now it's guaranteed to be 0
printf("array1[%d]: %d\n", i, array1[i]);
I really appreciate your help. I know it's somewhat of a noob question, but it came up as I was trying to get more comfortable with the C language and tried some non-book-example code.
If you suspect, that there might be something fundamental that I didn't get, please let me know, I'll read up on it.

Technically speaking, initialization can be done once and only at declaration time, any value storing after that is assignment or copying.
A brace-enclosed initializer list can be used for initialization of arrays only at the declaration time.
For an individual element of an array, (a scalar item), the rule is: (quoting C11, chapter §6.7.9)
The initializer for a scalar shall be a single expression, optionally enclosed in braces.
and an empty list {} is not a valid initializer (expression) for a scalar. hence you got the error.
So, for an already defined array, the re-setting has to be done either
member-by-member, via a loop
using memcpy(), or memset if so permits.

Related

Why does this initialize the first element only?

I'm trying to figure out why initializing an array with int buckets[AS] = { 0 }; is not setting all the elements to zero. Perhaps it is a compiler optimization, in which case would volatile be acceptable? volatile int buckets[AS] = { 0 };.
Second question, why is only the first element initialized to 1 here? Doesn't this fall under:
C99 [$6.7.8/21]
If there are fewer initializers in a brace-enclosed list than there are elements or members
of an aggregate, or fewer characters in a string literal used to initialize an array of known
size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.
Problem code:
#include <stdio.h>
#define AS 100
int buckets[AS] = { 1 };
int main()
{
int i;
for(i = 0; i < AS; i++) {
printf("%d", buckets[i]);
}
return 0;
}
EDIT:
Changing optimization level from -o0 to default eliminates the issue. Working with STM32 Kiel IDE micro-controllers.
EDIT EDIT:
This is the code causing trouble. Compiler optimizing away for loop?
// Initialize this to 1 as when initializing to 0 and clearing some elements are non-zero
// Possibly a compiler bug? Changing optimization level from -o0 to default eliminates the issue
uint16_t pulse_time_hist[NUM_BUCKETS] = {1};
// Resets all values stored in the histogram
void clearHist() {
unsigned int i;
for (i = 0; i < NUM_BUCKETS; i++) {
pulse_time_hist[i] = 0;
}
}
EDIT EDIT EDIT:
I'm not a compiler guy at all btw. Here is my compiler control string
-c -cpu Cortex-M4.fp -D__EVAL -g -O0 -apcs=interwork -split_sections ...
Running without -c99 currently.
In the quotation "... shall be initialized implicitly ..." a value for initialization is not mentioned, so rest of array is initialized by default value, and for number types this default value is 0.
To continue the topic try the following snippet
#include <stdio.h>
#define N 10
int arr1[N];
int main()
{
int arr2[N];
int i;
for (i = 0; i < N; i++) {
printf("%d ", arr1[i]);
}
printf("\n");
for (i = 0; i < N; i++) {
printf("%d ", arr2[i]);
}
return 0;
}
and try to understand why the output is
i.e. why global/static objects (like arr1) are initialized without initializers, but local/automatic/stack-allocated (like arr2) are not.
UPDATE:
Section 6.7.8 Initialization of C99 standard said:
If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. If an object that has static storage duration is not initialized explicitly, then:
— if it has pointer type, it is initialized to a null pointer;
— if it has arithmetic type, it is initialized to (positive or unsigned) zero;
— if it is an aggregate, every member is initialized (recursively) according to these rules;
— if it is a union, the first named member is initialized (recursively) according to these rules.
This is because the missing values are automatically initialized to zero. If you want to initialize every element to 1, you need to have this :
int buckets[AS] = {1, 1, 1, ..., 1}; //100 times
which clearly isn't feasible.
You may also want to read this answer as well.
int buckets[AS] = { 1 };
In which case you can omit some part of the initializer and the corresponding elements will be initialized to 0.
int buckets[AS] = { 1 }; //initialize to 1,0,0,0,0...
If you are trying to initialize all elements of the array to 1 there is a GCC extension you can use with the following syntax:
int buckets[AS] = {[0 … 99] = 1 };

Token pasting in c using a variable that increments

I have a set of arrays :msg1[] msg2[] .... msgn[] . And I need to use the values in a while loop. as msgi[]. When I define it as #define MSG(a) msg##a
and put it in a loop and increment i, it expands it to msgi?
You can't do it that way. Instead you could create a new array, that contains pointers to the actual arrays:
int array1[...];
int array2[...];
int *all_arrays[] = { array1, array2 };
build your c code with gcc -E myfile.c and you will see the reason
this called preprocessor code. the prprocessor code is the code generated by your compilator before the compilation. in this code the compilator replace the macros in your origin code with the content of the macro.
your origin code:
for (i=0; i<10; i++) {
for (j=0; j<10; j++)
MSG(i)[j] = 3;
}
preprocessr code generated from the origin code (could be seen with gcc -E):
for (i=0; i<10; i++) {
for (j=0; j<10; j++)
msgi[j] = 3;
}
You can use 2D array instead
int msg[5][5];
It can't be done cause macros are replaced at compilation time not runtime, so it will be replaced once...
what you could do is use 2D array if there are in the same size or use array of arrays if there are in different sizes:
//once in your code you need to do this:
int array0[];
int array1[];
//...
int arrayX[]; //X should be replaced with a real number...
int **arrayOfArrays = new (int*)[X+1];
arrayOfArrays[0] = array0;
arrayOfArrays[1] = array1;
//...
arrayOfArrays[X] = arrayX;
//now you could use it like that anytime in your code:
int i;
for(i = 0; i < X; ++i)
{
//Do whatever you want to do, like:
arrayOfArrays[i][0] = 1234;
}
When I define it as #define MSG(a) msg##a and put it in a loop and
increment i, it expands it to msgi?
No, it will not work that way, because the macro gets expanded before compilation, not after. You'll need a different approach, such as the 2D array suggested by #zakinster.
No, unfortunately it won't. C does not support runtime name lookups. Instead, you should use a two dimensional array of the form:
void** msg;
This will allow the arrays to be of different sizes and types, although you will have to cast to whatever type the array is.

what is "error: variable-sized object may not be initialized"?

I'm trying to fill an array with numbers from 1-100 with this code:
#include <stdio.h>
int main()
{
int num[100];
int i = 0;
for (i = 0; i < 100; i++)
{
int num[i] = i+1;
}
}
but I'm getting this error:
c:18:13: error: variable-sized object may not be initialized
I'm still relatively new to programming so I'm not sure what this means. Can you tell me?
Replace this
int num[i] = i+1;
For this:
num[i] = i+1;
You already declare the array on the top int num[100];
First you declare the array, and then you iterate over it inside the loop.
Since you are new, it is preferable you start by reading a good book about the subject my recommendation.
The problem is the int in int num[i] = i+1. The compiler thinks you're trying to declare a new array (also called num) with i elements in it (that's the variable-sized object part). Just remove the int from that line.
You are declaring the array again in the loop:
int num[i] = i+1;
Anyway, this is the error in your code but the problem for the compiler is not there: it gives you that error because that's not a valid declaration with initialization for an array. If you just write int num[i]; the code it's valid code and it will compile without error (well, only from C99, old C89 doesn't support variable-length arrays). This is what the compiler recognizes and tries to report.

max value in array C

I'm getting a compile errors, that I can't really fix. I need to create a program that initializes an in array, then write a biggest function that takes 2 parameters, an array and it's length and returns the index of the largest element in the array. I will then call this function from main. Can anyone tell me what is the problem?
errors:part1.c: part1.c: In function 'main':
part1.c:6:3: warning: implicit declaration of function 'largest'
part1.c:7:23: error: expected expression before ']' token
part1.c: In function 'largest':
part1.c:17:4: warning: statement with no effect
Thanks!
#include <stdio.h>
int main()
{
int myArray[]={1,2,3,4,5,6};
largest(myArray,6);
printf("%d",myArray[]);
return 0;
}
int largest(int array[], int length)
{
length = sizeof(array)/sizeof(array[0]);
int i = 1;
int max = array[0];
for(i; i<length; i++)
{
if(max < array[i])
{
max = array[i];
}
}
return max;
}
ISSUE 1
You use largest() in main() before you define it. Use a prototype, or move the definition above main().
ISSUE 2
In:
length = sizeof(array)/sizeof(array[0]);
You declare length as int length, but assign to it something of type size_t. That caused the error error: 'length' redeclared as different kind of symbol in the original version of your question.
ISSUE 3
In
for(i; i<length; i++)
you do not assign a value to i. Did you mean
for(i=0; i<length; i++)
? Although you did previously assign a value to i, I believe this is causing warning: statement with no effect (though hard to be sure without line numbers in the provided code).
Also, arrays in C are 0-based. You probably want to initialize i to 0 rather than 1.
ISSUE 4
In the line
printf("%d",myArray[]);
you use %d as a formatting specifier, which means that the supplied argument is expected to be an integer value. You supply an array instead.
C compiles your code in one pass. This means that everything should be defined before it is used. Your function largest is defined after its use, therefore once the compiler sees
largest(myArray,6);
it still doesn't know that largest exists!
The solution would be to either move the definition of largest above main, or better, forward declare the function:
#include <stdio.h>
int largest(int array[], int length);
int main()
{
int myArray[]={1,2,3,4,5,6};
largest(myArray,6);
printf("%d",myArray[]);
return 0;
}
int largest(int array[], int length)
{
/* implementation of largest */
}
Also, the sizeof(array) will not give you the number of elements in largest because that information is lost upon function call. You could move that expression up in the function call to compute and pass the length parameter:
largest(myArray,sizeof(myArray)/sizeof(myArray[0]));
This may also be a typo, but you probably meant to store and print the maximum value:
int max = largest(myArray,sizeof(myArray)/sizeof(myArray[0]));
printf("%d\n",max);
Put a declaration of largest() before main() to resolve the implicit declaration warning:
int largest(int array*, int length);
int main()
The error error: expected expression before ']' token is caused by:
printf("%d",myArray[]);
To print the largest value, you need to store the result of largest() or use it as an argument to printf():
printf("%d", largest(myArray, 6));
This is not what you expect:
length = sizeof(array)/sizeof(array[0]);
as arrays decays to pointers when passed as arguments. It is equivalent to:
length = sizeof(int*)/sizeof(int);
Just use the length argument to control the iteration. Recommend make the arguments to largest() const as the function does not modify them.
The warning: statement with no effect is caused by the i; in the for:
for(i; i<length; i++)
change to:
for(; i<length; i++)
or:
for(i = 0; i<length; i++)
or if C99:
for(int i = 0; i<length; i++)
You could also just move the definition of largest() above the definition of main() and it would work.
Many people have pointed out many issues but surprised no one has mentioned this:
int largest(int array[], int length)
{
length = sizeof(array)/sizeof(array[0]);
Nope, sizeof does not do what you appear to think it does here. It does not magically know the size of your allocations, only takes the size of the underlying type. What you have done is equivalent to sizeof(int*)/sizeof(int).
You should trust the length parameter the caller gave you. There's no way to get the actual size of the array using sizeof, only let the caller tell you how big it is.
You have an error and warnings .. the error is clearly more important.
printf("%d",myArray[]);
the %d format specification implies you want to write an int value, this is not the case, and the likely cause of your error.
There are other warnings that deserved your attention, such as not providing a function prototype for your 'largest` function etc, but those are secondary to fixing the error that prevents compilation.
Of course the warnings should also be eliminated, or a conscious decision should be made to ignore them after examining them.

Passing pointers of arrays in C

So I have some code that looks like this:
int a[10];
a = arrayGen(a,9);
and the arrayGen function looks like this:
int* arrayGen(int arrAddr[], int maxNum)
{
int counter=0;
while(arrAddr[counter] != '\0') {
arrAddr[counter] = gen(maxNum);
counter++;
}
return arrAddr;
}
Right now the compilier tells me "warning: passing argument 1 of ‘arrayGen’ makes integer from pointer without a cast"
My thinking is that I pass 'a', a pointer to a[0], then since the array is already created I can just fill in values for a[n] until I a[n] == '\0'. I think my error is that arrayGen is written to take in an array, not a pointer to one. If that's true I'm not sure how to proceed, do I write values to addresses until the contents of one address is '\0'?
The basic magic here is this identity in C:
*(a+i) == a[i]
Okay, now I'll make this be readable English.
Here's the issue: An array name isn't an lvalue; it can't be assigned to. So the line you have with
a = arrayGen(...)
is the problem. See this example:
int main() {
int a[10];
a = arrayGen(a,9);
return 0;
}
which gives the compilation error:
gcc -o foo foo.c
foo.c: In function 'main':
foo.c:21: error: incompatible types in assignment
Compilation exited abnormally with code 1 at Sun Feb 1 20:05:37
You need to have a pointer, which is an lvalue, to which to assign the results.
This code, for example:
int main() {
int a[10];
int * ip;
/* a = arrayGen(a,9); */
ip = a ; /* or &a[0] */
ip = arrayGen(ip,9);
return 0;
}
compiles fine:
gcc -o foo foo.c
Compilation finished at Sun Feb 1 20:09:28
Note that because of the identity at top, you can treat ip as an array if you like, as in this code:
int main() {
int a[10];
int * ip;
int ix ;
/* a = arrayGen(a,9); */
ip = a ; /* or &a[0] */
ip = arrayGen(ip,9);
for(ix=0; ix < 9; ix++)
ip[ix] = 42 ;
return 0;
}
Full example code
Just for completeness here's my full example:
int gen(int max){
return 42;
}
int* arrayGen(int arrAddr[], int maxNum)
{
int counter=0;
while(arrAddr[counter] != '\0') {
arrAddr[counter] = gen(maxNum);
counter++;
}
return arrAddr;
}
int main() {
int a[10];
int * ip;
int ix ;
/* a = arrayGen(a,9); */
ip = a ; /* or &a[0] */
ip = arrayGen(ip,9);
for(ix=0; ix < 9; ix++)
ip[ix] = 42 ;
return 0;
}
Why even return arrAddr? Your passing a[10] by reference so the contents of the array will be modified. Unless you need another reference to the array then charlies suggestion is correct.
Hmm, I know your question's been answered, but something else about the code is bugging me. Why are you using the test against '\0' to determine the end of the array? I'm pretty sure that only works with C strings. The code does indeed compile after the fix suggested, but if you loop through your array, I'm curious to see if you're getting the correct values.
I'm not sure what you are trying to do but the assignment of a pointer value to an array is what's bothering the compiler as mentioned by Charlie. I'm curious about checking against the NUL character constant '\0'. Your sample array is uninitialized memory so the comparison in arrayGen isn't going to do what you want it to do.
The parameter list that you are using ends up being identical to:
int* arrayGen(int *arrAddr, int maxNum)
for most purposes. The actual statement in the standard is:
A declaration of a parameter as "array of type" shall be adjusted to "qualified pointer to type", where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.
If you really want to force the caller to use an array, then use the following syntax:
void accepts_pointer_to_array (int (*ary)[10]) {
int i;
for (i=0; i<10; ++i) {
(*ary)[i] = 0; /* note the funky syntax is necessary */
}
}
void some_caller (void) {
int ary1[10];
int ary2[20];
int *ptr = &ary1[0];
accepts_pointer_to_array(&ary1); /* passing address is necessary */
accepts_pointer_to_array(&ary2); /* fails */
accepts_pointer_to_array(ptr); /* also fails */
}
Your compiler should complain if you call it with anything that isn't a pointer to an array of 10 integers. I can honestly say though that I have never seen this one anywhere outside of various books (The C Book, Expert C Programming)... at least not in C programming. In C++, however, I have had reason to use this syntax in exactly one case:
template <typename T, std::size_t N>
std::size_t array_size (T (&ary)[N]) {
return N;
}
Your mileage may vary though. If you really want to dig into stuff like this, I can't recommend Expert C Programming highly enough. You can also find The C Book online at gbdirect.
Try calling your parameter int* arrAddr, not int arrAddr[]. Although when I think about it, the parameters for the main method are similar yet that works. So not sure about the explanation part.
Edit: Hm all the resources I can find on the internet say it should work. I'm not sure, I've always passed arrays as pointers myself so never had this snag before, so I'm very interested in the solution.
The way your using it arrayGen() doesn't need to return a value. You also need to place '\0' in the last element, it isn't done automatically, or pass the index of the last element to fill.
#jeffD
Passing the index would be the preferred way, as there's no guarantee you won't hit other '\0's before your final one (I certainly was when I tested it).

Resources