I have tried this example of array of pointers. I am getting the error "Illegal initialisation in function main"
int main()
{
int a[]={1,2,3,4,5};
int b[]={1,2,3,4,5};
int c[]={1,2,3,4,5};
int *p[3]={a,b,c};
int i;
clrscr();
for(i=0;i<3;i++)
printf("%d - %u\n",*p[i],p[i]);
getch();
}
If I use static int instead of int in array declarations, it works fine. Can any one tell me the effect of static here. Thanks a lot.
In gcc you see warnings about this if you use the -pedantic flag.
But this is apparently something that has changed in the standard, in C90 it say:
All the expressions in an initializer for an object that has static
storage duration or in an initializer list for an object that has
aggregate or union type shall be constant expressions
and it was not allowed as the p array is an aggregate type, but in C99 we have:
All the expressions in an initializer for an object that has static
storage duration shall be constant expressions or string literals.
This compiles fine with gcc and gcc -ansi. gcc -ansi -pedantic however gives the following warning:
blackjack.c: In function ‘main’:
blackjack.c:8: warning: initializer element is not computable at load time
blackjack.c:8: warning: initializer element is not computable at load time
blackjack.c:8: warning: initializer element is not computable at load time
Whereas line 8 is:
int *p[3]={a,b,c};
As I see it the problem is that at the time a, b, and c would be stored in p, they don't exist yet. That's because they will be put on the stack and the position on the stack depends on things outside the scope of a function. To clarify this, 'load time' means the time the program is loaded into memory, not the time it is already in execution. (Don't ask me why/how it works anyway)
try:
printf("%d - %u\n",*(p[i]),p[i]);
although I have a feeling you're trying to do something more like:
int a[]={1,2,3,4,5};
int b[]={1,2,3,4,5};
int c[]={1,2,3,4,5};
int *p[3]={a,b,c};
int i;
clrscr();
for(i=0;i<sizeof(p)/sizeof(int*);i++) {
for (int j =0; j < sizeof(a)/sizeof(int); j++) {
printf("%d - %u\n",(p[i])[j],p[i]);
}
}
getch();
The rules are pretty simple.For static objects the initialization list should be constant.No such restriction exists for the elements that will be allocated space on stack.
It appears logical too,as the static objects need to be written in the data section and the compiler must be able to resolve their values beforehand.
On stack memory is allocated once the function in question(main) is called.So no problem there.I don't know why the opposite behavior on turbo-c.
on gcc this happens:(on compiling with gcc -Wall prog.c
int *p[]={a,b,c} //works fine
static int *p[]={a,b,c} //oops blunder
Related
I am learning C right now and have a problem understanding something about the behaviour of a program with a static variable. As far as i know, static simply increases the scope of a variable to the file containing it.
#include <stdio.h>
int sum (int num) {
static int sum =0;
sum=sum+num;
return sum;
}
int main() {
printf("%d ",sum(55));
printf("%d ",sum(45));
printf("%d ",sum(50));
return 0;
}
if i execute this i get 55 100 150 as an output. And that's totally fine and expected.
Then i thought could decraese one line by changing it a little bit like this:
int sum (int num) {
static int sum =0+num;
return sum;
}
but this returns 55 55 55
I don't understand why it only returns 55 and doesn't add the other variables, that i am giving in the main to it.
When you declare a static variable inside a function instead of outside a function it can only be accessed inside the function. Otherwise it works like a global variable in the sense that it exists throughout the lifetime of the program. Its initial value is determined when the program is compiled so it must be initialized with a constant expression. Any decent compiler should warn you if the initializer is not constant as in your example:
$ gcc -o test -Wall test.c
test.c: In function ‘sum’:
test.c:3:24: error: initializer element is not constant
static int sum =0+num;
^
Note that you should always compile your C programs with warnings enabled.
By default C variables exist only within the block where they are declared. They are said to be of automatic storage class.
By using the keyword static you are able to declare a variable of static storage class, i.e. a variable that exist for all the duration of the program.
Even though static variables exist during the whole program execution, they can be accessed only within the block in which they are declared.
Scope and storage class are two different things.
I have read in multiple places that when declaring an extern variable, the memory is not designated until the definition is made. I was trying this code which is giving contradictory output in gcc.
#include <stdio.h>
int main() {
extern int a;
printf("%lu", sizeof(a));
return 0;
}
it should have shown error or zero size. but the output was following. please justify the output. Is it example of another undefined behavior?
aditya#theMonster:~$ ./a
4
You're able to get away with it here because a is never actually used. The expression sizeof(a) is evaluated at compile time. So because a is never referenced, the linker doesn't bother looking for it.
Had you done this instead:
printf("%d\n", a);
Then the program would have failed to link, printing "undefined reference to `a'"
The size of a variable is the size of its data type, whether it is presently only an extern or not. Since sizeof is evaluated at compile time, whereas symbol resolution is done at link time, this is acceptable.
Even with -O0, gcc doesn't care that it's extern; it puts 4 in esi for the argument to printf: https://godbolt.org/z/Zv2VYd
Without declaring a, however, any of the following will fail:
a = 3;
printf("%d\n", a);
int *p = &a;
The a is an integer, so its size is 4.
Its location(address) and value are not currently known.(it is extern somewhere at some other location)
But the size is well defined.
size_t sizeof(expr/var_name/data_type) 1 is a unary operator which when not provided with a variable length array, do not evaluate the expression. It just check the data type of expression.
Similarly, here, in sizeof(a), the complier only checks the data type of a which is int and hence returns the size of int.
Another example to clear your confusion is in sizeof(i++), i do not get incremented. Its data type is checked and returned.
One more example:
void main(){
int p=0;
printf("%zu",sizeof(p=2+3.0));
printf("%d",p);
}
will give u output on gcc as:
4
0
There is indeed a problem in your code, but not where you expect it:
passing a value of type size_t for printf conversion specification %ld has undefined behavior if size_t and unsigned long have different sizes or representations, as is the case on many systems (16-bit systems, Windows 64-bit...).
Here is a corrected version, portable to non C99-conforming systems, whose C library printf might not support %zu:
#include <stdio.h>
int main(void) {
extern int a;
printf("%lu\n", (unsigned long)sizeof(a));
return 0;
}
Regarding why the program compiles and executes without an error:
Variable a is declared inside the body of main with extern linkage: no space is allocated for it and a would be undefined outside the body of main.
sizeof(a) is evaluated at compile time as the constant value sizeof(int), which happens to be 4 on your platform.
No further reference to a is generated by the compiler, so the linker does not complain about a not being defined anywhere.
I was writing the following code
#include<stdio.h>
void fun(int n) {
int a[n] = {0};
}
void main() {
int a[4] = {0};
int i = 0;
fun(3);
}
and got this error
test.c: In function 'fun':
test.c:5:5: error: variable-sized object may not be initialized
while if I change the function fun to:-
void fun(int n) {
int a[n], i = 0;
for(i = 0; i < n; i++) {
a[i] = 0;
}
}
it works fine.
I know that the error is occuring because it's not allowed in the compiler's specification but what i want to know is why is it not possible to be implemented?
Is it due to some compile time or run time evaluation issue?
I have seen the answer of other question but i need a more elaborated answer.
Variable Length Array cannot be initialized like this
int a[n]={0};
From C Standards#6.7.9p3 Initialization [emphasis added]
The type of the entity to be initialized shall be an array of unknown size or a complete object type that is not a variable length array type.
Using loop is one way to initialize the variable length array's. You can also use memset like this:
memset(a, 0, sizeof a);
Additional:
The C99 compiler should support the Variable Length Array's but they were made optional in C11 compiler.
An easy way is to send the size of array along with other parameters
Remember that you should send size before an array with that size
void fun(int n,int a[n]){
}
Although you have other alternatives like sizeof()
As an addition to H.S. answer:
From C Standards#6.7.9p3 Initialization [emphasis added]
The type of the entity to be initialized shall be an array of unknown size or a complete object type that is not a variable length array type.
This is probably because Initializers have to be constant expressions. Constant expression have a definite value at compile time.
A {0} is an incomplete Initializer and the compiler would fill up the remaining values with 0.
If you have a VLA the compiler does not know the length of the Array and thus can not generate the initializer for it.
This depends on your compiler actually.
In old C You couldn't have variable size arrays. In function fun you use a as an array with variable size n. This is not allowed in old C. However, C99 and C11 standards support variable size arrays, so perhaps you have an old compiler. (DevC?) If you want to use some type of variable arrays in older C compilers, you have to use malloc and free.
Perhaps you wanted to write this code in C++? C++ doesn't support variable size arrays also, but the gcc compiler can run this code.
Check this out:
Why aren't variable-length arrays part of the C++ standard?
If you are using DevC, I think that if you change your file from test.c to test.cpp this code will work.
Okay, so this is a stripped down variant of a bug I had. The bug was that I initialized an array using a variable that wasn't initialized. Earlier I used a function to declare the number of elements using a function, but after a cleanup I forgot about it and moved all declarations to the top of the function.
I used the flags -std=c99 -Wall -Wextra -pedantic -O, and usually gcc warns about values being used before they are uninitialized, but in this specific case it didn't. So, my question is:
Is this a bug in gcc or is it possible for f(&n) to post-initialize the array size in some weird way?
#include <stdio.h>
void f(int * x) {
*x = 8;
}
int main(void) {
int n;
float a[n]; // Compiler should warn that n may contain garbage
a[7] = 3.1415;
printf("%f\n", a[7]);
f(&n); // Removing this causes the compiler warn as expected
return 0;
}
EDIT: It may be this gcc bug?
GCC is accepting float a[n] as a variable-length array. It should, however, warn you that n contains garbage when it’s used. Perhaps VLA initialization is getting rearranged in a way that makes that fact non-obvious to the code generator? If n were initialized before use, moving the call to f() above the declaration of a would clearly be wrong, but this program produces undefined behavior.
My understand has always been that when I declare an array on the stack with a size that comes in as a variable or parameter, I should get an error.
However, I noticed that I do not get any error if I do not explicitly initialize the array (yes, it won't be on the stack, but I'm wondering about the lack of error).
For example, the following code does not compile because of array2:
#define N 30
void defineArrays(int n)
{
int i,j;
int array1[N] = {};
int array2[n] = {};
for(i=0; i<N; ++i) array1[i] = 0;
for(j=0; j<n; ++j) array2[j] = 0;
}
But the following code compiles and runs, even when I send a real n from main:
#define N 30
void defineArrays(int n)
{
int i,j;
int array1[N] = {};
int array2[n];
for(i=0; i<N; ++i) array1[i] = 0;
for(j=0; j<n; ++j) array2[j] = 0;
}
What I am missing here? Is it declaring array2 as a pointer?
I'm using gcc
Update: Thanks for everyone who answered. The problem was indeed that my version of gcc was defaulting to C99 for some strange reason (or not so strange, maybe I'm just too old), and I incorrectly assumed that it defaults to C90 unless I tell it otherwise.
C99 introduced the ability to have variable length arrays which is now available in GCC (although it's reported as not being totally standards compliant). In the second example, you appear to be taking advantage of that functionality.
Link to GCC's info about variable length arrays: http://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
I think that you need to choose you C standard version.
gcc -fsyntax-only -std=c89 -pedantic -x c -
<stdin>: In function ‘defineArrays’:
<stdin>:6: warning: ISO C forbids empty initializer braces
<stdin>:8: warning: ISO C90 forbids variable length array ‘array2’
vs.
gcc -fsyntax-only -std=c99 -pedantic -x c -
<stdin>: In function ‘defineArrays’:
<stdin>:6: warning: ISO C forbids empty initializer braces
Declaring the array with an initializer forces the array to be static (created at compile time) even though the scope is within the function. The compiler cannot define the array at compile time because it does not then know the value of 'n'.
When I compile the first example with gcc, it gives me this error:
error: variable-sized object may not be initialized
I imagine this is not allowed because you don't know how big n will be, and therefore you can't be sure that it will be big enough to hold all the elements you are trying to initialize. That is, suppose you have code like this:
int array2[n] = { 1, 2, 3, 4 };
This requires that array2 have (at least) 4 slots. What if n is passed in as zero?
The second example does not have this problem because you are not making any implicit statement about the size of array2.
Hope that helps,
Eric Melski