why do I need the curly braces here? - c

Consider this simple program:
fails.c:
#include <stdio.h>
int main(){
int i = 10;
if (i == 10)
int j = 11;
return 0;
}
That fails to compile (gcc fails.c), giving this error:
fails.c: In function ‘main’:
fails.c:7:3: error: expected expression before ‘int’
int j = 11;
^
But this one goes through just fine:
#include <stdio.h>
int main(){
int i = 10;
if (i == 10){
int j = 11;
}
return 0;
}
I figured that the work around, is to put those {} in. But I wish to know why this is required.
Why does it behave this way, when something like printf is acceptable?
#include <stdio.h>
int main(){
int i = 10;
if (i == 10)
printf("some text\n");
return 0;
}

This is because if must be followed by a statement:
C99/6.8.4
if ( expression ) statement
However, a declaration is not a statement:
C99/6.8
statement:
labeled-statement
compound-statement
expression-statement
selection-statement
iteration-statement
jump-statement
When put inside a {}, it is a compound-statement, thus ok.

There is a difference between declaration and statement.
int j = 11;
is a declaration. if statement shall be followed by a statement. Putting {} after if statement results in a compound statement. A compound statement can have no other statement in it or can have a declaration.

It seems you compile your ANSI C code with C89 standard. And, unlike his successor C99, it requires all variables to be declared at the beginning of the scope. So, having int j = 11; somewhere in-between other statements just contradicts that C89 rule. If you open a new scope just before that int j = 11;, it's back to OK.
Actual reason of such C89 limitation should be an attempt to simplify memory management for stack-allocable variables. For instance, compare it with Pascal language that requires all variables to be declared in the special var section before the code (so, it's even more strict that C89).

Related

Can someone explain variables declaration in C

I'm new to programming, I'm taking this online programming course CS50. So I had an assignment to write a program in C, where user inputs some words (no matter how much space there is before or after words) and we have to print first initials of each word. So I made this program:
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
int n;
int i;
string name = get_string();
if(name != NULL)
{
if (name[0] != ' ')
{
printf("%c", toupper(name[0]));
}
for(i = 0, n = strlen(name); i < n; i++)
{
if(name[i] ==' ' && isalpha(name[i+1]))
{
printf("%c", toupper(name[i+1]));
}
}printf("\n");
}
}
But it was correctly done only after I declared variables int n; int i;
Before that, I could not even compile program. Why? At first I declared int i
in for loop, but program didn`t even compiled. And just out of luck I tried to declare outside loop and its correct. I dont understand this point. Can someone explain? :)
All variables and functions must be declared before they may be used. The variable i must be declared before it can be used as an index in the for loop.
Under the 1989/1990 standard and earlier K&R language versions, all declarations had to come before any executable statements in a block:
void foo( void )
{
/**
* The variable i is used to control a for loop later on in the function,
* but it must be declared before any executable statements.
*/
int i;
/**
* Some amount of code here
*/
for( i = 0; i < some_value; i++ ) // K&R and C90 do not allow declarations within the loop control expression
{
/**
* The variable j is used only within the body of the for loop.
* Like i, it must be declared before any executable statements
* within the loop body.
*/
int j;
/**
* Some amount of code here
*/
j = some_result();
/**
* More code here
*/
printf( "j = %d\n", j );
}
}
As of the 1999 standard, declarations may be mixed with other statements, and they may appear as part of the initial expression of a for loop:
void foo( void )
{
/**
* Some amount of code here
*/
for ( int i = 0; i < some_value; i++ ) // C99 and later allow variable declarations within loop control expression
{
/**
* Some code here
*/
int j = some_result(); // declare j when you need it
/**
* More code here
*/
printf( "j = %d\n", j );
}
}
The chief difference between the two snippets above is that in the first case, i is visible over the body of the entire function, whereas in the second snippet, it's only visible within the body of the for loop. If you need i to be visible to any code following the for loop, then you need to declare it outside the loop control expression:
int i;
for ( i = 0; i < some_value; i++ )
{
...
}
...
do_something_with( i );
Again, i must be declared before it can be used in the loop control expression; it's just in the second case, that declaration is part of the loop control expression.
EDIT
I don't know what development environment or compiler you are using. You might want to see if you can specify which version of the language you want to compile against (for example, in gcc, you'd specify -ansi or -std=c90 for the 1989/1990 version and -std=c99 for the 1999 version).
First of all - welcome to C language! I think C is a great language to start with.
Variables declaration - in C, we are allowed to declare on a local variable only at the beginning of a scope - at the very beginning of a function, loop, if statement, etc.
For example:
We can't run this:
for(int i = 0; i<4: ++i) { printf("%d",i); }
The declaration is in the for statement - not at the beginning of the scope. In C++, this code will work.
However, we can do the following:
int foo()
{
int i;
for(i=0;i<4; i++) { ...}
}
Remark: local variables and parameters passed are allocated on stack. When we declare on a local variable we push the variable into the stack and we get to the end of the scope - the variable pops out.

Global variable does not take new value

I was making a simple C program
#include<stdio.h>
static int a;
a = 5;
int main()
{
printf("%d",a);
return 0;
}
Compiler error: "non static declaration of 'a' follows static declaration"
What does this error mean?
what this error log means?
It is a little tricky: what looks like an assignment
a = 5;
is treated as
int a = 5;
due to an old C rule that allowed you to declare int variables and int-returning functions without specifying their type explicitly (this is definitely not a good idea in the modern version of C).
Note that this is treated as a declaration with an implicit int only in the scope outside a function body.
You can fix it by combining the declaration with initialization, like this:
static int a = 5;
Outside a function you can only declare variables, you cannot have actual code statements.
a = 5;
is being interpreted as another declaration, when your intent I think is to write some code.
instead declare and initialise a at the same time
static int a = 5;
Your first declaration of a is static (ahas internal linkage).
The second declaration is not static (a has external linkage). Yes, a = 5; is a declaration with implicit type int in this case.
Both do not agree.
Btw. for functions this would be o.k. because the second declaration would "inherit" the internal linkage.
We cannot write any assignment statement globally. For example:
#include <stdio.h>
static int i=10; //Initialization statement
i=25; //Assignment statement
int main(){
printf("%d",i);
return 0;
}
Output: Compilation error
Note: Assigning any value to the variable at the time of declaration is known as initialization while assigning any value to variable not at the time of declaration is known assignment.
You can't set value as you did it: a = 5; before main(...). See code below:
static int a = 1; //default = 0;
int main()
{
printf("a = %d\n", a);
a = 2;
printf("a = %d\n", a);
return 0;
}
Output:
a = 1
a = 2
A = 5 is considered as an attempt to create another variable called a. You should put the = 5 after static int a.
Static int a = 5;
Just a little modification to your code will help you to understand it.
#include<stdio.h>
//static int a; //comment this statement
a = 5;
int main()
{
printf("%d",a);
return 0;
}
now compile this code [please enable your compiler's warnings]
Then you will get a warning something like this
data definition has no type or storage class [enabled by default]
So now try to understand this warning it means that compiler treat statement a=5 as a definition but without data type. But compiler unable default data type that is int.
so this statement is equivalent to
int a=5;

C error: Expected expression before int

When I tried the following code I get the error mentioned.
if(a==1)
int b =10;
But the following is syntactically correct
if(a==1)
{
int b = 10;
}
Why is this?
This is actually a fairly interesting question. It's not as simple as it looks at first. For reference, I'm going to be basing this off of the latest C11 language grammar defined in N1570
I guess the counter-intuitive part of the question is: if this is correct C:
if (a == 1) {
int b = 10;
}
then why is this not also correct C?
if (a == 1)
int b = 10;
I mean, a one-line conditional if statement should be fine either with or without braces, right?
The answer lies in the grammar of the if statement, as defined by the C standard. The relevant parts of the grammar I've quoted below. Succinctly: the int b = 10 line is a declaration, not a statement, and the grammar for the if statement requires a statement after the conditional that it's testing. But if you enclose the declaration in braces, it becomes a statement and everything's well.
And just for the sake of answering the question completely -- this has nothing to do with scope. The b variable that exists inside that scope will be inaccessible from outside of it, but the program is still syntactically correct. Strictly speaking, the compiler shouldn't throw an error on it. Of course, you should be building with -Wall -Werror anyways ;-)
(6.7) declaration:
declaration-specifiers init-declarator-listopt ;
static_assert-declaration
(6.7) init-declarator-list:
init-declarator
init-declarator-list , init-declarator
(6.7) init-declarator:
declarator
declarator = initializer
(6.8) statement:
labeled-statement
compound-statement
expression-statement
selection-statement
iteration-statement
jump-statement
(6.8.2) compound-statement:
{ block-item-listopt }
(6.8.4) selection-statement:
if ( expression ) statement
if ( expression ) statement else statement
switch ( expression ) statement
{ } -->
defines scope, so if(a==1) { int b = 10; } says, you are defining int b, for {}- this scope. For
if(a==1)
int b =10;
there is no scope. And you will not be able to use b anywhere.
By C89, variable can only be defined at the top of a block.
if (a == 1)
int b = 10; // it's just a statement, syntacitially error
if (a == 1)
{ // refer to the beginning of a local block
int b = 10; // at the top of the local block, syntacitially correct
} // refer to the end of a local block
if (a == 1)
{
func();
int b = 10; // not at the top of the local block, syntacitially error, I guess
}

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.

For loop says expression syntax error when initializing integer in the loop

While programming I have come to an unusual error. When I initialize an integer in a loop, sometimes it says that the expression is not valid, but at times it accepts it.
This is my code which gives error:
int pow(int x,int n);
int main()
{
int x,n,result;
printf("Enter a number:\n");
scanf("%d",&x);
printf("Enter its power:\n");
scanf("%d",&n);
result=pow(x,n);
printf("Result is %d\n",result);
getch();
return 0;
}
int pow(int x,int n)
{
for(int i=1;i<n;i++) //<-- here it says that declaration syntax error
x=x*i;
return x;
}
While when i change it like this :
int pow(int x,int n)
{
int i;
for(i=1;i<n;i++)
x=x*i;
return x;
}
C89 and earlier versions only support declaration statements at the head of a block (IOW, the only thing that can appear between an opening { and a declaration is another declaration):
/* C89 and earlier */
int main(void)
{
int x; /* this is legal */
...
for (x = 0; x < 10; x++)
{
int i; /* so is this */
printf("x = %d\n", x);
int j = 2*x; /* ILLEGAL */
}
int y; /* ILLEGAL */
...
}
With C99, declaration statements can appear pretty much anywhere, including control expressions (with the caveat that something must be declared before it is used):
// C99 and later, C++
int main(void)
{
int x; // same as before
...
for (int i = 0; i < 10; i++) // supported as of C99
{
printf("i = %d\n", i);
int j = 2 * i; // supported as of C99
}
int y; // supported as of C99
}
Turbo C predates the C99 standard, so if you want to write code like in the second example, you will need to use a more up-to-date compiler.
In C, before C99, you need to declare your variables before your loop. In C++, and now in C99, you can declare them within the loop as you try here. The different results you are getting may be because you are sometimes compiling as C++, and sometimes compiling as C.
You could try to make sure you are always compiling your code as C++, or if you're using GCC or Clang, compile with the --std=c99 flag. C99 is unsupported by MSVC, so you will either need to use C++ or move the declaration outside of the loop if you're using MSVC.
It sounds like you have a C89 compiler (rather than C99 compiler).
In C89, you are only allowed to declare variables at the beginning of a function. You are simply not allowed to declare variables elsewhere in a function, including in the initialization part of a for statement. That's why the second syntax works and the first fails.
The second syntax is valid for C99 and C++ but not for C89.
What C compiler are you using?
Older versions of C prior to C99 require all variable declarations be made at the top of a code block.

Resources