Why does this initialize the first element only? - c

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 };

Related

variable sized object may not be initialized even after using const for the variable

I use the const for assigning the variable but the array shows an error "variable-sized object may not be initialized"
#include <stdio.h>
int main()
{
const int city=10;
const int week=2;
int arr[city][week]={34,34,64,23,65,22,65,77,42,74,22,88,46,34,77,53,63,457,234,723};
for(int i=0;i<city;i++)
{
for(int j=0;j<week;j++)
{
printf("%d",arr[city][week]);
}
}
}
You are using const qualified variables for your array dimension and not "integer constant expressions". For C, this means that your array is a variably modified type, for which C does not allow initializers.
As others already told you, if initialization would be allowed, the syntax has to be = and not ==.
You have several issues.
you've posted it in the subject, is that you can't use const int for the array length and then initialize it, because it will become a variable-sized object, and you can't initialize it in with constant numbers. You can use #ifdef to define city/week, and then it will not happen.
You've used compare (==) instead of assignment (=)
change:
int arr[city][week]=={34,34,64,23,65,22,65,77,42,74,22,88,46,34,77,53,63,457,234,723};
to:
int arr[city][week]={34,34,64,23,65,22,65,77,42,74,22,88,46,34,77,53,63,457,234,723};
you need to change your printf and probably add line break:
printf("%d\n",arr[i][j]);
so to summarize:
#include <stdio.h>
#define city 10
#define week 2
int main()
{
int arr[city][week]={34,34,64,23,65,22,65,77,42,74,22,88,46,34,77,53,63,457,234,723};
for(int i=0;i<city;i++)
{
for(int j=0;j<week;j++)
{
printf("%d\n", arr[i][j]);
}
}
}
== compares, = assigns
you even would print the same output
i would also prefer to use {a,b},{c,d}...

Use Initialization List in C after declaration

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.

What is the problem with the following piece of code?

This piece of code seems to be creating some troubles while compiling. Any explanation?
int i =20;
int maxlen = i;
int main()
{
int j = i;
printf("i=%d , j=%d\n", i , j);
}
In C, you can't initialize global variables using non-constant expressions. Initializing maxlen to i fails because i is not a constant expression. It's part of the C standard.
Why not #define a constant?
#define MAXLEN 20
You can only use compile-time constants when initializing a variable at that scope. Try:
int i = 20;
int maxlen;
int main()
{
maxlen = i; // assign within the scope of a function
int j = i;
printf("i=%d , j=%d\n", i , j);
}
This Code is Invalid in C but valid in C++:
C - http://www.ideone.com/mxgMo
Error Reason -: initializer element is not constant
C++ - http://www.ideone.com/XzoeU
Works.
Because:
The C++ Standard states:
3.6.1 Main function [basic.start.main]
1 A program shall contain a global function called main, which is the designated start of the program. It is implementation defined whether a program in a freestanding environment is required to define a main function. [ Note: in a freestanding environment, start-up and termination is implementation-defined; start-up contains the execution of constructors for objects of namespace scope with static storage duration; termination contains the execution of destructors for objects with static storage duration. —end note ]
However, C99 says this:
56.7.8 Initialization
4 All the expressions in an initializer for an object that has static storage duration
shall be constant expressions or string literals.
So not just the code you posted, but something like this will also be invalid in C:
#include<stdio.h>
int needint(void);
int i =needint();
int needint(void)
{
return 1;
}
int main()
{
int j = i;
printf("i=%d , j=%d\n", i , j);
}
See here.

Define integer (int); What's the default value?

int i;
int data[5] = {0};
data[0] = i;
What's the value in data[0]?
Also, what's the meaning of this line?
if (!data[0]) { ... }
In most cases, there is no "default" value for an int object.
If you declare int i; as a (non-static) local variable inside of a function, it has an indeterminate value. It is uninitialized and you can't use it until you write a valid value to it.
It's a good habit to get into to explicitly initialize any object when you declare it.
It depends on where the code is written. Consider:
int i;
int data[5] = {0};
void func1(void)
{
data[0] = i;
}
void func2(void)
{
int i;
int data[5] = {0};
data[0] = i;
...
}
The value assigned to data[0] in func1() is completely deterministic; it must be zero (assuming no other assignments have interfered with the values of the global variables i and data).
By contrast, the value set in func2() is completely indeterminate; you cannot reliably state what value will be assigned to data[0] because no value has been reliably assigned to i in the function. It will likely be a value that was on the stack from some previous function call, but that depends on both the compiler and the program and is not even 'implementation defined'; it is pure undefined behaviour.
You also ask "What is the meaning of this?"
if (!data[0]) { ... }
The '!' operator does a logical inversion of the value it is applied to: it maps zero to one, and maps any non-zero value to zero. The overall condition evaluates to true if the expression evaluates to a non-zero value. So, if data[0] is 0, !data[0] maps to 1 and the code in the block is executed; if data[0] is not 0, !data[0] maps to 0 and the code in the block is not executed.
It is a commonly used idiom because it is more succinct than the alternative:
if (data[0] == 0) { ... }
if an integer is declared globally then it is initialized automatically with zero
but if it is local then contains garbage value until and unless itis given some value
If an integer is not initialized, its value is undefined as per C
Since you've included the ={0};, the entire array is filled with zeros. If this is defined outside any function, it would be initialized with zeros even without the initializer. if (!data[x]) is equivalent to if (data[x] == 0).
// File 'a.c'
#include <stdio.h>
void main()
{
int i, j , k;
printf("i = %i j = %i k = %i\n", i, j, k);
}
// test results
> $ gcc a.c
> $ ./a.out
> i = 32767 j = 0 k = 0

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