Scope of a variable and function name - c

This is my code:
#include <stdlib.h>
#include <stdio.h>
int sum(int,int);
int sum(int x, int size) {
int sum = 0;
printf("%p\n", &x);
printf("%p\n", &size);
printf("%p\n", &sum);
sum(x,size);
return 0;
}
int main() {
sum(2,4);
return 0;
}
And the error I am getting is:
hello.c:11:5: error: called object type 'int' is not a function or function pointer
sum(x,size);
~~~^

You changed the meaning of sum here:
int sum = 0;
From now on, in the scope in which it was declared, sum is an int, and this becomes nonsense:
sum(x,size); /* Wat? sum is an int!!! */
Don't do that, and your code will compile. Once it compiles, you can worry about stopping the recursion.

If you define two separate identifiers of same name for different entities in the same name space, they might overlap. C11 standard, chapter §6.2.1 states,
If an identifier designates two different entities in the same name
space, the scopes might overlap....
Refer Footnote: Why in this scenario, both sums are in same name space
So, once you re-define the identifier with some other type,
....If so, the scope of one entity (the inner scope) will end
strictly before the scope of the other entity (the outer scope). Within the inner scope, the identifier designates the entity declared in the inner scope; the entity declared in the outer scope is hidden (and not visible) within the inner scope.
That means, essentially, in your case, inside function sum(), when you're defining int sum, basically you're shadowing the function sum. After the re-definition, sum is an identifier of type int, in that function scope. Thus, inside the function sum(), you cannot make a call to sum() as that is an int type now.
However, FWIW, the call to sum() in main() (or, rather, outside sum() itself) should be valid, as at that point, int sum will be out of scope.
Solution: Change the int sum variable name to something else.
Thanks to #pmg for the correction
EDIT:
As mentioned in the other answer by #juanchopanza, after changing the shadowing variable name, your program will compile and once you run it, you'll face infinite recursion due to the unconditional call to sum() inside sum() itself. You need to add some break condition to end (return from) the recursion.
FootNote:
Referring to C11, chapter §6.2.3, name spaces, we can say, there are separate name spaces for various categories of identifiers, e.g. 1) label names 2) the tags of structures, unions, and enumerations, 3) the members of structures or unions and 4) all other identifiers.
So, in this particular case, the function sum() and the int sum definition will reside in the same name space, for the sum() function scope

The scope matters
Function name sum here has a global scope.
Variable sum is local and has local scope.
The conflict is because inside sum() you call sum(). Now inside function sum() you have 2 objects of same name and of different type hence the error.
If you had something like
int sum()
{
int sum = 0;
sum = 10;
printf("%d\n",sum);
}
Then your code would have been fine. Since variable sum is local to function sum() and it is the only object within function sum() with that name.
Instead of worrying about this better to rename the variable and make sure variable name and function name is different

You need to change int sum = 0 to int y = 0, also your program will break as you dont stop recursion at sum(x,sum)

Simply change variable sum name inside sum function to total
#include <stdlib.h>
#include <stdio.h>
int sum(int,int);
int sum(int x, int size) {
int total = 0;
printf("%p\n", &x);
printf("%p\n", &size);
printf("%p\n", &total);
sum(x,size);
return 0;
}
int main() {
sum(2,4);
return 0;
}

Variable and function is of same name thats why it is de-referencing function and variable same time thats the cause of error

Related

the defined variable is different

why is the variable in the average function is different from the same variable in the main function? I do not know how to solve it because I'm just learning.
#include <stdio.h>
#define SIZE (sizeof(number)/sizeof(int))
int number[] = {5,65,84,25,644,2};
int average(int *number)
{
printf("size = %ld\n",SIZE);
int sum=0;
for(int i=0;i<=SIZE ;i++)
{
sum += number[i];
}
return sum/SIZE;
}
int main()
{
printf("average : %d\n",average(number));
printf("number of elements: %ld\n", SIZE);
return 0;
}
You use a macro (i.e. #define ...) to specify SIZE. The macro is expanded "textually" wherever you make use of it, and it is interpreted in the respective context, i.e. it's meaning depends on where you place it.
So in main, number as part of your macro refers to the global variable number, whereas in the context of function average, it refers to the function argument number (which hides the equally named global variable).
Anyway, it's impossible to deduce any array size from a pointer variable. You'll have to pass the number of elements as an extra argument.
Within main, number is a global variable which is an array. So sizeof(number) gives you the size of the whole array in bytes.
In the average function however, number is a parameter to the function and has type int *. So sizeof(number) in that case gives you the size of the pointer, not the size of the array.
Either don't pass a parameter and just use the global, or pass the size of the array as a separate parameter to the function.
You have defined a global variable number which is an array.
In the function average , you defined another variable with the same name/identifier number (although of different type i.e. a pointer).
Now, when you use number inside the main function you are actually using the pointer number and not the global variable number. This is also known as variable hiding.
If you want to use the global variable change the name of the argument of the average function to something else or you can go the hard way and do something like this.
Happy Coding;)

Why tentative definition concept in C not valid for local variables [duplicate]

When I compile the code below
#include<stdio.h>
int main()
{
int a;
int a = 10;
printf("a is %d \n",a);
return 0;
}
I get an error:
test3.c: In function ‘main’:
test3.c:6:5: error: redeclaration of ‘a’ with no linkage
test3.c:5:5: note: previous declaration of ‘a’ was here
But if I make the variable global then it works fine.
#include<stdio.h>
int a;
int a = 10;
int main()
{
printf("a is %d \n",a);
return 0;
}
Why is declaring the same global variable twice not an error, but doing that for a local variable is an error?
In C, the statement int a; when made at file scope, is a declaration and a tentative definition. You can have as many tentative definitions as you want, as long as they all match each other.
If a definition (with an initializer) appears before the end of the translation unit, the variable will be initialized to that value. Having multiple initialization values is a compiler error.
If the end of the translation unit is reached, and no non-tentative definition was found, the variable will be zero initialized.
The above does not apply for local variables. Here a declaration also serves as a definition, and having more than one leads to an error.
The other reason I could think of is that un-initialized global variables are stored in the BSS (Block Structured Segment) where are the global variables that are initialized are stored in Data Segment.
I am guessing that there is some kind of a name space resolution and when there is a conflict the variable in the Data segment overrides the one in the Block Structured Segment.
if you were to declare
int a =5
int a = 10
in the global scope (both in the data segment) there would be conflict as expected.
You can't have two global variables with the same name in C program.
C might allow multiple definitions in the same file scope through the tentative definition rule, but in any case all definitions will refer to the same variable.
Local Variable
In C, multiple local variables are not "merged" into one.
All the local variables with the same name will be referring to the different int-sized piece of memory.
#include<stdio.h>
int main()
{
int a;
int a = 10;
printf("a is %d \n",a);
return 0;
}
So when assigning the memory to the redeclaration of the same variable it gives an Error.
Global Variable
In C, multiple global variables are "merged" into one. So you have indeed just one global variable, declared multiple times. This goes back to a time when extern wasn't needed (or possibly didn't exist - not quite sure) in C.
In other words, all global variables with the same name will be converted to be one variable - so your
#include<stdio.h>
int a;
int a = 10;
int main()
{
printf("a is %d \n",a);
return 0;
}
will be referring to the same int-sized piece of memory.

Why doesn't declaring a variable with the same name outside and inside a loop produce an error?

{
int i;
for(i=0;i<5;i++)
{
int i=10;
printf("%d",i);
}
}
I have two questions
Why is there no redeclaration error for i?
why output will be 10 5 times and not 10 1 time?
It all has to do with the scope of an identifier. An identifier is simply a name given to an entity (object, function, typedef name and so on) in C and, as per C11 6.2.1 /1:
The same identifier can denote different entities at different points in the program.
The scope of an entity is described in /2 of that section:
For each different entity that an identifier designates, the identifier is visible (i.e., can be used) only within a region of program text called its scope.
And /4 covers your specific case:
If an identifier designates two different entities in the same name space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end strictly before the scope of the other entity (the outer scope).
In other words, something like:
{
int i = 42;
printf ("%d ", i);
{
int i = 17;
printf ("%d ", i);
}
printf ("%d\n", i);
}
is perfectly valid, and will print 42 17 42. That's because the identifier i inside the inner block is in its own scope, which ends at the first closing brace.
In your particular case, you can think of it as:
{
int i; \
for(i=0;i<5;i++) > outer i scope
{ /
int i=10; \
printf("%d",i); > inner i scope
} /
}
The inner int i=10 effective hides the outer i for the duration of the body of the for loop. That's why it prints a lot of 10s rather than 0..4.
The scope of the inner i finishes at the closing brace of the for loop body so that, when the continuation condition of the for loop is checked, it once again sees the outer i. That's why it loops five times rather than once.
In your code
int i; is in outer block scope.
int i=10; is in the inner block scope for the for loop
If we visualize the same, we can come up with something like'
{ //---------------------------|
int i; |
for(i=0;i<5;i++) |
{ |
int i=10; //-------| inner scope |> Outer scope
printf("%d",i); //-------| |
} |
} //----------------------------|
The case here is, the inner i will shadow the outer i. These two are considered seperate variable (based on their scope).
In other words, the i which is defined and present inside the block (inner scope) will have more preference (over the variable in outer scope). So, the inner i value will get printed.
OTOH, the loop counter variable i remains at the outer scope. It's value is not altered through the assignement inside the block. So, rightly it loops for 5 times, as asked.
Related: From C11 standard, chapter §6.2.1, paragraph 4,
..[..].. If an identifier designates two different entities in the same name
space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end strictly before the scope of the other entity (the outer scope). Within the inner scope, the identifier designates the entity declared in the inner scope; the entity declared in the outer scope is hidden (and not visible) within the inner scope.
So, to answer your questions,
Why is there no redeclaration error for i?
Because two is are treated as seperate variable, despite being named same.
why output will be 10 5 times and not 10 1 time?
Because, the outer i, used as the counter, is not changed from inside the loop, only the loop increment condition is altering that value.
You aren't re-declaring i since the second declaration of i ( 'int i =10' ) is inside a loop . That's means that in your example the variable is destroyed and recreated for each iteration of the loop .
The scope of variables created in any compound statement is limited to the compound statement itself .
Ps : If you wanted to stop the loop by changing the value of i
{
int i;
for(i=0;i<5;i++)
{
i=10;
printf("%d",i);
}
}
If you ask your compiler nicely (gcc -Wshadow) it will warn you
echo -e '#include <stdio.h>\nvoid f(void) { int i; for (i = 0; i < 5; i++) { int i = 10; printf("%d", i); } }' | gcc -Wshadow -xc -c -
<stdin>: In function 'f':
<stdin>:2:53: warning: declaration of 'i' shadows a previous local [-Wshadow]
<stdin>:2:20: note: shadowed declaration is here

Duplicated identifier for a variable in function local scope

So, this is code from a student of my friend…
#include <stdio.h>
int main(){
int hours;
int take_one_number(void);{
scanf("%d",&hours);
}
int minutes;
int take_one_number(void);{
scanf("%d",&minutes);
}
int seconds;
int take_one_number(void);{
scanf("%d",&seconds);
}
int all;
printf("%d",all=hours*3600+minutes*60+seconds);
return all;
}
Well, it… compiles… and… uhm, works… as requested by the teacher…
My question: if I understand correctly, take_one_number here is a definition of a variable to store a function pointer. Why does neither GCC nor LLVM complain about a duplicated identifier in these definitions?
The function take_one_number is declared 3 times, but never defined. In each case, the ; after the (void) ends the declaration. The scanf statement is then just a regular statement inside of main(), surrounded by a meaningless scope { }
In the above code ,
int take_one_number (void);
is not a function pointer , it is function prototype or declaration , a function can be declared more than once , but must be defined only once.
int take_one_number(void);
It's a function declaration whose return type is int. It's not a definition of a variable. And the scoping you did for variables has little meaning here as no variable declaration is happening in it.
int take_one_number(void); is a function prototype to tell the compiler that there is a function implemented somewhere with this name and property. Compiler does not complain because you are neither defining new function nor using that function.
You should also note that the blocks that follow after this prototype are not part of the take_one_number as they are separated with semi-colon. Making the blocks as independent scope blocks. To make things more clearer there would be compilation error if there were no semi-colon between the function prototype and the code block next to it.

How do global and static variables work together in C?

I have to determine the output of this program (without running it on the computer). I am pretty unsure on how the global and static variables work together.
#include <stdio.h>
void f(int d);
int a = 1, b = 2, c = 3, d = 4;
int main()
{
int a = 5, c = 6;
f(a);
f(b);
f(c);
printf("%d %d %d %d\n",a,b,c,d);
return 0;
}
void f(int d)
{
static int a = 0;
a = a + 7;
b = a + d;
c++;
d--;
printf("%d %d %d %d\n",a,b,c,d);
}
Local variable defintions always "hide" global variables with the same name. An inner scope always takes precedence over an outer one. Some compilers also produce warning when a variable "shadows" another one.
The nearest visible binding in scope hides all the further ones. So in main all the names refer to the local variables, and in f only a is the local one (albeit static, that's immaterial), d refers to the function parameter, and b and c refer to the global ones.
You can unhide farther-away names to a limited extend with the extern keyword, but given enough local scopes you can always create and hide variables that you can never see from somewhere deeper.
If two variables are declared with the same identifier, the accesses refer to the one with the smallest scope.
C11 (n1570), § 6.2.1 Scopes of identifiers
If an identifier designates two different entities in the same name
space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end
strictly before the scope of the other entity (the outer scope). Within the inner scope, the
identifier designates the entity declared in the inner scope; the entity declared in the outer
scope is hidden (and not visible) within the inner scope.

Resources