C Static Variables and Static Functions Explained with Examples

by Himanshu Arora on August 3, 2012

In C language, the life time and scope of a variable is defined by its storage class.

The following are four types of storage class available in C language.

  1. auto
  2. register
  3. extern
  4. static

In this article, we will discuss the ‘static’ storage class and explain how to use static variables and static functions in C with some sample code snippets.

Before moving ahead, lets quickly understand the difference between life time and scope of a variable. A region in code where a variable can be accessed is known as its scope and the duration during which a variable remains active is known as its life time.

I. Static Variables

1. Impact on Life Time

static variables are those variables whose life time remains equal to the life time of the program. Any local or global variable can be made static depending upon what the logic expects out of that variable. Lets consider the following example :

#include<stdio.h>

char** func_Str();

int main(void)
{
    char **ptr = NULL;

    ptr = func_Str();
    printf("\n [%s] \n",*ptr);

    return 0;
}

char** func_Str()
{
    char *p = "Linux";
    return &p;
}

In the code above, the function ‘func_str()’ returns the address of the pointer ‘p’ to the calling function which uses it further to print the string ‘Linux’ to the user through ‘printf()’. Lets look at the output :

$ ./static 

 [Linux]
$

The output above is as expected. So, is everything fine here? Well, there is a hidden problem in the code. More specifically, its the return value of the function ‘func_Str()’. The value being returned is the address of the local pointer variable ‘p’. Since ‘p’ is local to the function so as soon as the function returns, the lifetime of this variable is over and hence its memory location becomes free for any further modifications.

Lets prove this observation. Look at the code below :

#include<stdio.h>

char** func1_Str();
char** func2_Str();

int main(void)
{
    char **ptr1 = NULL;
    char **ptr2 = NULL;

    ptr1 = func1_Str();
    printf("\n [%s] \n",*ptr1);

    ptr2 = func2_Str();
    printf("\n [%s] \n",*ptr2);

    printf("\n [%s] \n",*ptr1);

    return 0;
}

char** func1_Str()
{
    char *p = "Linux";
    return &p;
}

char** func2_Str()
{
    char *p = "Windows";
    return &p;
}

In the code above, now there are two functions ‘func1_Str()’ and ‘func2_Str()’. The logical problem remains the same here too. Each of these function returns the address of its local variable. In the main() function, the address returned by the func1_Str() is used to print the string ‘Linux’ (as pointed by its local pointer variable) and the address returned by the function func2_Str() is used to print the string ‘Windows’ (as pointed by its local pointer variable). An extra step towards the end of the main() function is done by again using the address returned by func1_Str() to print the string ‘Linux’.

Now, lets see the output :

$ ./static 

 [Linux] 

 [Windows] 

 [Windows]
$

The output above is not as per expectations. The third print should have been ‘Linux’ instead of ‘Windows’. Well, I’d rather say that the above output was expected. Its just the correct scenario that exposed the loophole in the code.

Lets go a bit more deep to see what happened after address of local variable was returned. See the code below :

#include<stdio.h>

char** func1_Str();
char** func2_Str();

int main(void)
{
    char **ptr1 = NULL;
    char **ptr2 = NULL;

    ptr1 = func1_Str();
    printf("\n [%s] :: func1_Str() address = [%p], its returned address is [%p]\n",*ptr1,(void*)func1_Str,(void*)ptr1);

    ptr2 = func2_Str();
    printf("\n [%s] :: func2_Str()address = [%p], its returned address is [%p]\n",*ptr2,(void*)func2_Str,(void*)ptr2);

    printf("\n [%s] [%p]\n",*ptr1,(void*)ptr1);

    return 0;
}

char** func1_Str()
{
    char *p = "Linux";
    return &p;
}

char** func2_Str()
{
    char *p = "Windows";
    return &p;
}

The code is above is modified to print the address of the functions and the address of their respective local pointer variables. Here is the output :

$ ./static 

 [Linux] :: func1_Str() address = [0x4005d5], its returned address is [0x7fff705e9378]

 [Windows] :: func2_Str()address = [0x4005e7], its returned address is [0x7fff705e9378]

 [Windows] [0x7fff705e9378]
$

The above output makes it clear that once the lifetime of the local variable of the function ‘func1_Str()’ gets over then same memory address is being used for the local pointer variable of the function ‘func2_Str()’ and hence the third print is ‘Windows’ and not ‘Linux’.

So, now we see what that the root of the problem is the life time of the pointer variables. This is where the ‘static’ storage class comes to rescue. As already discussed the static storage class makes the lifetime of a variable equal to that of the program. So, lets make the local pointer variables as static and then see the output :

#include<stdio.h>

char** func1_Str();
char** func2_Str();

int main(void)
{
    char **ptr1 = NULL;
    char **ptr2 = NULL;

    ptr1 = func1_Str();
    printf("\n [%s] :: func1_Str() address = [%p], its returned address is [%p]\n",*ptr1,(void*)func1_Str,(void*)ptr1);

    ptr2 = func2_Str();
    printf("\n [%s] :: func2_Str()address = [%p], its returned address is [%p]\n",*ptr2,(void*)func2_Str,(void*)ptr2);

    printf("\n [%s] [%p]\n",*ptr1,(void*)ptr1);

    return 0;
}

char** func1_Str()
{
    static char *p = "Linux";
    return &p;
}

char** func2_Str()
{
    static char *p = "Windows";
    return &p;
}

Note that in code above, the pointers were made static. Here is the output :

$ ./static 

 [Linux] :: func1_Str() address = [0x4005d5], its returned address is [0x601028]

 [Windows] :: func2_Str()address = [0x4005e0], its returned address is [0x601020]

 [Linux] [0x601028]

So we see that after making the variables as static, the lifetime of the variables becomes equal to that of the program.

On a related note, if you are not familiar with C pointers, this C pointer series of articles should give you a jump start.

2. Impact on Scope

In case where code is spread over multiple files, the static storage type can be used to limit the scope of a variable to a particular file. For example, if we have a variable ‘count’ in one file and we want to have another variable with same name in some other file, then in that case one of the variable has to be made static. The following example illustrates it :

Here we use two files (static.c and static_1.c)

//static.c

#include<stdio.h>

int count = 1;

int main(void)
{
    printf("\n count = [%d]\n",count);

    return 0;
}
// static_1.c

#include<stdio.h>

int count = 4;

int func(void)
{
    printf("\n count = [%d]\n",count);
    return 0;
}

Now, when both the files are compiled and linked together to form a single executable, here is the error that is thrown by gcc :

$ gcc -Wall static.c static_1.c -o static
/tmp/ccwO66em.o:(.data+0x0): multiple definition of `count'
/tmp/ccGwx5t4.o:(.data+0x0): first defined here
collect2: ld returned 1 exit status
$

So we see that gcc complains of multiple declarations of the variable ‘count’.

As a corrective measure, this time one of the ‘count’ variable is made static :

//static.c

#include<stdio.h>

static int count = 1;

int main(void)
{
    printf("\n count = [%d]\n",count);

    return 0;
}
// static_1.c

#include<stdio.h>

int count = 4;

int func(void)
{
    printf("\n count = [%d]\n",count);
    return 0;
}

Now, if both the files are compiled and linked together :

$ gcc -Wall static.c static_1.c -o static
$

So we see that no error is thrown this time because static limited the scope of the variable ‘count’ in file static.c to the file itself.

II. Static Functions

By default any function that is defined in a C file is extern. This means that the function can be used in any other source file of the same code/project (which gets compiled as separate translational unit). Now, if there is a situation where the access to a function is to be limited to the file in which it is defined or if a function with same name is desired in some other file of the same code/project then the functions in C can be made static.

Extending the same example that was used in previous section, suppose we have two files :

//static.c

#include<stdio.h>

void func();

int main(void)
{
    func();
    return 0;
}

void funcNew()
{
    printf("\n Hi, I am a normal function\n");
}
// static_1.c

#include<stdio.h>

void funcNew();

int func(void)
{
    funcNew();
    return 0;
}

If we compile, link and run the code above :

$ gcc -Wall static.c static_1.c -o static
$ ./static 

 Hi, I am a normal function
$

So we see that the function funcNew() was defined in one file and successfully got called from the other. Now, if the file static_1.c wants to have its own funcNew(), ie :

// static_1.c

#include<stdio.h>

void funcNew();

int func(void)
{
    funcNew();
    return 0;
}

void funcNew()
{
    printf("\n Hi, I am a normal function\n");
}

Now, if both the files are compiled and linked together :

$gcc -Wall static.c static_1.c -o static
/tmp/ccqI0jsP.o: In function `funcNew':
static_1.c:(.text+0x15): multiple definition of `funcNew'
/tmp/ccUO2XFS.o:static.c:(.text+0x15): first defined here
collect2: ld returned 1 exit status
$

So we see that the compiler complains of multiple definitions of the function funcNew(). So, we make the funcNew() in static_1.c as static :

// static_1.c

#include<stdio.h>

static void funcNew();

int func(void)
{
    funcNew();
    return 0;
}

static void funcNew()
{
    printf("\n Hi, I am also a normal function\n");
}

Now, if we compile, then we see that the compiler never complains :

$ gcc -Wall static.c static_1.c -o static
$ ./static 

 Hi, I am also a normal function
$

Similarly, if static.c wants that its funcNew() should be accessible from within static.c only then in that case funcNew() in static.c can be made static.


Linux Sysadmin Course Linux provides several powerful administrative tools and utilities which will help you to manage your systems effectively. If you don’t know what these tools are and how to use them, you could be spending lot of time trying to perform even the basic administrative tasks. The focus of this course is to help you understand system administration tools, which will help you to become an effective Linux system administrator.
Get the Linux Sysadmin Course Now!

If you enjoyed this article, you might also like..

  1. 50 Linux Sysadmin Tutorials
  2. 50 Most Frequently Used Linux Commands (With Examples)
  3. Top 25 Best Linux Performance Monitoring and Debugging Tools
  4. Mommy, I found it! – 15 Practical Linux Find Command Examples
  5. Linux 101 Hacks 2nd Edition eBook Linux 101 Hacks Book

Bash 101 Hacks Book Sed and Awk 101 Hacks Book Nagios Core 3 Book Vim 101 Hacks Book

{ 31 comments… read them below or add one }

1 Jalal Hajigholamali August 3, 2012 at 9:30 am

Hi,

Thanks a lot,
I sent this article to my students in university

2 Himanshu Arora August 3, 2012 at 11:37 am

@Jalal
Thanks for the appreciation.

3 Bobbum_Man August 3, 2012 at 12:15 pm

Nice article. Could you also explain what Register storage class means?

4 Thiago Jobson August 5, 2012 at 9:58 am

Great article.
There was another thing I did not know :
“By default any function that is defined in a C file is extern. ”

Thanks alot;

5 Jay August 8, 2012 at 1:26 am

Awesome article. Really cleared up quite a few doubts. Keep up the good work :)

6 Adorn August 8, 2012 at 8:18 am

Basic thing Explained very neatly!

7 Tariq November 8, 2012 at 2:58 pm

I am wondering why Himanshu is using double pointer to point to the character. Secondly, if the local memory is gone after the function returns, why is Linux getting printed in the first example?

8 nikoo28 January 29, 2013 at 9:45 am

Thanks a lot for this article…really really helpful….

9 Anjaneya Alluri January 30, 2013 at 10:14 pm

while explaining Impact of static on Lifetime , the second printf statement of (*ptr1) is returning null.( not windows ).
My main doubt is , why did it even print the value of Linux the first time ?
Also , if i try to add a second printf immediately after my first printf of (*ptr1) , even then it is printing null.

So its printing only once . why ?

10 Neo February 14, 2013 at 10:09 pm

Its really helpful!!! Thanks for posting! :)

11 Gufran February 27, 2013 at 1:28 am

Many many thanks buddy for posting such a great article :)

12 Balaganesh March 8, 2013 at 7:07 am

This case is before using static keyword:
How the local variable contents are printed in main (). Actually the stack created for each function will get destroyed once we return from it.But how it gets printed ???
And whether the 2 functions are using the same stacks ??? because the address are same

13 Chanchal March 30, 2013 at 12:20 am

A great tutorial, really liked it..

14 mohd salman May 22, 2013 at 11:47 pm

hi, i m salman BCA 2nd sem. this website is very usefull for my and your study. I realy thanks for it.

15 vineet kumar June 12, 2013 at 8:18 am

Thanks for explaining so clearly about the static variable and funtions.
Thanks alot

16 anuj August 9, 2013 at 2:48 pm

nice work

17 Tejas Patel August 28, 2013 at 12:12 am

Excellent job.

18 jameel Ahmed September 18, 2013 at 11:48 am

Hi
could u please explain the use of double pointer in the programs u have used

19 akg September 24, 2013 at 4:22 am

good job…

20 Nahla October 1, 2013 at 8:06 pm

Thanks so much it very useful

21 dbhat October 9, 2013 at 2:57 am

Thanks a lot …. Nice work :)

22 Daniel Mendonça October 9, 2013 at 7:31 pm

Wow, thanks a lot, really easy to understand your examples, and the use of it.
Thanks

23 Anil October 22, 2013 at 6:22 am

than k u so much …for posting…nice articel,i have read so many websites about the static functions no one explained clearly…really….than k u so much….

24 Krishna Narendrula October 29, 2013 at 12:15 am

Hi,

Thanks a lot for this….I am expecting some more

25 vijay November 12, 2013 at 10:06 am

excellent..

26 WicTy December 19, 2013 at 6:33 am

This is super awesome. Thank you!

27 anurag March 20, 2014 at 5:01 am

how does the value of the local variable get printed despite it being destroyed from the stack once the function returns.

28 Gene April 17, 2014 at 2:57 pm

Very good explanation. I just needed a confirmation of what I already guessed is true about local variables and lifetimes. Thank you.

29 Swaroop May 13, 2014 at 11:23 pm

Thank for great explanation..

30 Vinay Gayki May 21, 2014 at 12:56 am

well explained ,good job ..thanks :-)

31 Karthik May 25, 2014 at 10:18 pm

Thank you vary much Sir,
but I have one small doubt. As follows
#include

char** func1_Str();
char** func2_Str();

int main(void)
{
char **ptr1 = NULL;
char **ptr2 = NULL;

ptr1 = func1_Str();
printf(“\n [%s] :: func1_Str() address = [%p], its returned address is [%p]\n”,*ptr1,(void*)func1_Str,(void*)ptr1);

ptr2 = func2_Str();
printf(“\n [%s] :: func2_Str()address = [%p], its returned address is [%p]\n”,*ptr2,(void*)func2_Str,(void*)ptr2);

printf(“\n [%s] [%p]\n”,*ptr1,(void*)ptr1);

return 0;
}

char** func1_Str()
{
static char *p = “Linux”;
return &p;
}

char** func2_Str()
{
static char *p = “Windows”;
return &p;
}
In this example can we use global variables instead of static? If it is then what is the specific usage of static variable here?

Leave a Comment

Previous post:

Next post: