Local variable and static variables - c

I just want to understand the difference in RAM allocation.
Why if i define a variable before function i have a RAM overflow and when i define it inside a function it is ok?
For example:
/*RAM OK*/
void Record(int16_t* current, int i,int n)
{
float Arr[NLOG2] = {0};
for(i=0;i<n;i++)
Arr[i]=current[i*5];
}
/*RAM OVERFLOW*/
static float Arr[NLOG2] = {0};
void Record(int16_t* current, int i,int n)
{
for(i=0;i<n;i++)
Arr[i]=current[i*5];
}
This is the message:
unable to allocate space for sections/blocks with a total estimated
minimum size of 0x330b bytes (max align 0x8) in
<[0x200000c8-0x200031ff]> (total uncommitted space 0x2f38).

The difference is that in the first case, Arr is declared on the stack; until the function is called, that array doesn't exist. The generated binary contains code for creating the array, but the array itself isn't in the binary.
In the second case, however, Arr is declared outside of any function (aka at file scope). Therefore, it always exists, and is stored in the binary. Because you appear to be working on an embedded platform, this otherwise insignificant difference causes your "RAM overflow" error.

In the 2nd case, the array is allocated when the application starts. It remains in the memory until the app quits.
In the 1st case, the array is only allocated when function void Record(int16_t* current, int i,int n) is called. The array is gone after the function finishes its execution.
static keyword doesn't have any impact if you have only a single compilation unit (.o file).
Global variables (not static) are there when you create the .o file available to the linker for use in other files. Therefore, if you have two files like this, you get name collision on a:
a.c:
#include <stdio.h>
int a;
int compute(void);
int main()
{
a = 1;
printf("%d %d\n", a, compute());
return 0;
}
b.c:
int a;
int compute(void)
{
a = 0;
return a;
}
because the linker doesn't know which of the global as to use.
However, when you define static globals, you are telling the compiler to keep the variable only for that file and don't let the linker know about it. So if you add static (in the definition of a) to the two sample codes I wrote, you won't get name collisions simply because the linker doesn't even know there is an a in either of the files:
a.c:
#include <stdio.h>
static int a;
int compute(void);
int main()
{
a = 1;
printf("%d %d\n", a, compute());
return 0;
}
b.c:
static int a;
int compute(void)
{
a = 0;
return a;
}
This means that each file works with its own a without knowing about the other ones.

Related

C static variables initialization

I learned some C and came across an explanation for static variables.
They showed this code:
#include<stdio.h>
int fun()
{
static int count = 0;
count++;
return count;
}
int main()
{
printf("%d ", fun());
printf("%d ", fun());
return 0;
}
I can't understand why calling the function twice is fine, because the line
static int count = 0;
actually runs twice...
I can't understand how is that possible...
Can you actually declare it twice or does the compiler just ignore it the second time?
This (statics/globals) is where an initializing definition is really different from an uninitialized definition followed by an assignment.
Historically, the former even used to have different syntax (int count /*no '=' here*/ 0;).
When you do:
int fun() {
static int count = 0;
//...
}
then except for the different scopes (but not lifetimes) of count, it's equivalent to:
static int count = 0; //wider scope, same lifetime
int fun() {
//...
}
In both cases, the static variable becomes initialized at load time, typically en-masse with other statics and globals in the executable.
static variables are initialized on program startup, not every time the function is called.
... because the line static int count = 0; actually runs twice.
No. Just once, right before main() is called.

strange transition between integer and array

I have defined a global variable SEIS_FORMAT as an integer. But when I use it in the external function, I define it as an array SEIS_FORMAT[6] and use it as SEIS_FORMAT[0], as follows:
1.MAIN() code:
#include "head.h"
int SEIS_FORMAT=5; /*global variable*/
int main()
{
int a=2;
float b=3.5;
f1(&a, &b);
return 0;
}
2.function code: "f1.c"
#include "head.h"
void f1(int *a, float *b)
{
extern int SEIS_FORMAT[6]; //different from the main()
printf("a=%d,b=%f,c=%d\n",*a,*b,SEIS_FORMAT[0]); //notice the use of SEIS_FORMAT
}
Why can I always get the correct answer: a=2,b=3.500000,c=5?
The definitions of SEIS_FORMAT are equivalent to each other?
This is almost certainly undefined behavior, so anything is possible.
As to why it seems to work, the linker doesn't know anything about data types, it just knows that the name SEIS_FORMAT refers to a specific memory location. It's initialized by the main program as a single integer, but f1() then treats that memory location as the beginning of an array. Element 0 of the array corresponds to the integer that was initialized in the main program.

Global Array Issues Not Updating, C Programming

I have a program distributed across a number of files. There are a number of functions which need access to a global array. The issue I'm having is that I don't know the size of the array before the program starts. It opens up a file and then downloads a number of points, and then the array is created with a corresponding size. But for the array to be global, it needs to be declared outside of the main function i.e. before I know the number of points.
What I've tried to do right now is:
file1.c:
#include <stdio.h>
#include "file3.h"
int useful[];
int main()
{
int useful[10];
int i;
for (i = 0; i < 10; i++) {
useful[i] = i+1;
}
SPN();
return 0;
}
file2.c:
#include <stdio.h>
#include "file3.h"
void SPN() {
int i;
for (i = 0; i < 10; i++) {
printf("%i\n", useful[i]);
}
}
file3.h:
extern int useful[];
extern void SPN();
What I'm getting in output is just a bunch of 0s. At first I was thinking that the second int useful[... in file1.c creates a new array with a different internal name, but that doesn't seem to make any sense considering that no segmentation fault is triggered by SPN() when it tries to access memory outside the arrays bounds (if useful[] creates an array and isn't changed, it has default size 1 i.e. < 10). Help?
The int useful[10]; isn't initializing the global int useful[]; or anything like that. It's a new variable, and with the loop here
for (i = 0; i < 10; i++) {
useful[i] = i+1;
}
You're modifying the second useful without touching the global one. This is then discarded at the end of the function.
Instead have a global variable like this:
int *useful;
And initialize it this way:
useful = malloc(sizeof(int)*10);
The declaration of useful inside the main is shadowing the external one.
This means that the values that you think are inserting (in the main) in the global variable are actually going into the local variable.
Take a look at the following article about shadowing for more info.
It might also be interesting to look at scope rules in C.

Change random memory location on purpose between two executions in c

I sometimes want to show my students that local variables have to be initialized before use. But on some occasions they get the initial value of zero without being initialized. So my students don't believe me. For example in this code.
#include <stdio.h>
int main(void){
int sum;
sum += 5;
printf("%d", sum);
return 0;
}
Sometimes output is 5. To demonstrate the undefined behaviour of not initialising the variable sum to zero I am looking for an example.
Pointing to standards is good. But I understand your desire to show an example to your students. I'm not sure about the best way; but to increase your chances of seeing the undefined behavior, you can declare multiple variables that cannot easily be optimized away by the compiler.
#include <stdio.h>
void main(){
int sum1;
int sum2;
int sum3;
int sum4;
int sum5;
int sum6;
int sum7;
int sum8;
int sum9;
int sum=sum1+sum2+sum3+sum4+sum5+sum6+sum7+sum8+sum9;
printf("%d\n",sum);
}
On my system; recent Ubuntu, with recent GCC this produces incorrect results on every run, whereas your original example always produced 5. But I can't make any guarantees for your system.
Memory is usually initialized to zero when a process is started. Otherwise, you would get old memory contents from another process, which would be a security risk. Because of this, code like this will, in my experience, usually print zero:
#include <stdio.h>
int main(void) {
int x;
printf("%d\n", x);
}
You have a greater chance to get non-zero results if you use memory that has been used by your own process. For example, I just got non-zero printouts with this program:
#include <stdio.h>
void f(void) {
int x;
printf("%d\n", x);
}
int main(void) {
f();
f();
f();
}
But remember that according to the standard, the contents of an uninitialized local variable (with storage class auto) is undefined, so a compiler is allowed to always set its variables to zero. Or -4.
How about explicitly setting the value for a certain position and reading it from another uninitialized variable pointing at the same position?
#include <stdio.h>
void foo()
{
int x = 1234;
}
void bar()
{
int y;
printf("%d\n", y);
}
int main()
{
foo();
bar(); /* Will print out 1234 */
}
It would be better to not prove your students something by your self instead use C standards.
C99 section 6.7.8 Initialization:
If an object that has automatic storage duration is not initialized
explicitly, its value is indeterminate.

Creating an array during run-time and passing it to a function in C?

I'm getting some input from the user in the main() function and create an array accordingly. Because of the nature of the location of this array it is not visible to other functions and I need to pass it to a few other functions for processing.
Is there any way to do this without allocating memory for it and passing a pointer to that allocated memory?
flight is structure typedef.
int main()
{
do{ // Read # of flights from user
printf("Enter max number of flights to read in from file\n");
printf("--> ");
fflush(stdin);
} while(!(scanf("%d",&num_of_flights)));
flight database[num_of_flights]; // Create database for flights
In C you can allocate memory during runtime in such way
#include <stdlib.h>
#include <stdio.h>
void print_array(int *array, int array_size){
for(int i = 0; i < array_size; ++i){
printf("%d ", *(array + i));
}
}
int main(){
int *array;
int array_size;
scanf("%d", &array_size);
array = malloc(sizeof(int) * array_size);
// Fill array with ints
for(int i = 0; i < array_size; i++){
*(array + i) = i;
}
print_array(array, array_size);
return 0;
}
This shows how you might use malloc on a struct and then use the malloc'd item as a parameter to other functions
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct fl {
int distance;
char aeroplane[30];
char startgeo[2];
};
typedef struct fl flight;
void show_flight_data(flight d) {
printf("distance %d aeroplane %s",d.distance, d.aeroplane);
}
int main()
{
int num_of_flights;
flight *database;
do{ // Read # of flights from user
printf("Enter max number of flights to read in from file\n");
printf("--> ");
fflush(stdin);
} while(!(scanf("%d",&num_of_flights)));
database=(flight *)malloc(sizeof(flight) * num_of_flights);
database[0].distance = 100;
database[1].distance = 200;
strcpy(database[0].aeroplane, "777");
strcpy(database[1].aeroplane, "Airbus");
show_flight_data(database[0]);
return(0);
}
From the C standard, 6.2.4 Storage durations of objects:
The lifetime of an object is the portion of program execution during
which storage is guaranteed to be reserved for it. An object exists,
has a constant address) and retains its last-stored value
throughout its lifetime....
An object whose identifier is declared with no linkage and without the
storage-class specifier static has automatic storage duration...
For such an object that does not have a variable length array type,
its lifetime extends from entry into the block with which it is
associated until execution of that block ends in any way.
So, the lifetime of database extends until the execution of its enclosing block ends. That block is the body of main, so it is alive until main returns or the program exits. Therefore, you can simply pass database to other functions, or even store its address in a global that is accessed by other functions ... there is no need to allocate space and copy it.
BTW, you should be aware that by defining database[num_of_flights], where num_of_flights is not a constant, you are using a relatively recent feature of C -- variable length arrays (VLA's) -- and that some prominent C compilers (cough, Visual Studio, cough) do not support them.

Resources