COMP2017 & COMP9017: Systems Programming
C Crash Course (I): C Basics
for System Programming
Presented by
Dr. Shuaiwen Leon Song
USYD Future System Architecture Lab (FSA)
https://shuaiwen-leon-song.github.io/
https://shuaiwen-leon-song.github.io/
COMMONWEALTH OF AUSTRALIA
Copyright Regulations 1969
WARNING
This material has been reproduced and communicated to you by or on behalf of
the University of Sydney pursuant to Part VB of the Copyright Act 1968 (the Act).
The material in this communication may be subject to copyright under the Act. Any
further copying or communication of this material by you may be the subject of
copyright protection under the Act.
Do not remove this notice.
Acknowledgement
Some material in these slides was based on lectures by Dr. John
Stavrakakis from COMP2017/COMP9017, A/Prof Bob Kummerfeld
and Prof Judy Kay
Reading material: https://www.cs.rochester.edu/u/ferguson/csc/c/c-for-
java-programmers.pdf
The C Programming Language (K&R)
https://www.cs.rochester.edu/u/ferguson/csc/c/c-for-java-programmers.pdf
An interesting question
Q: Hi there,
I am confused why a scalable system need to maintain the same efficiency as processors are
added? Why don’t we think about improving the efficiency?
A: It is one of the metrics to measure scalability. Because scalable systems’ speedup are
bounded by the increasing number of processors while increasing problem size can help
improve the speedup. On the page 2 of the paper, it clearly shows this. No systems can scale
linearly so what is the best way to increase the problem size with respect to the number of
processors to keep the keep the efficiency fixed (please see the following paper for
definition). Iso-efficiency metric helps answer this. You can think about improving the
efficiency if the baseline is bad. But what if the efficiency is good, how can you maintain it
while you scale your system size? That is the question it tries to answer. Please read the paper:
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.416.729&rep=rep1&type=pdf
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.416.729&rep=rep1&type=pdf
C-Language
› Mainly usedfor
– Systems software (OS, embedded systems, etc.)
– Software that needs hardware interaction
› Also..
– Application programming, science/engineering, etc.
› C-Compilers exist for nearly all computerarchitectures
› A very popular language
› C does not have features suchas
– Objects and Classes
– Templates
– Operator/Function overloading
› C++ overcomes this and is a successor ofC
› Writing a non-optimizing C-Compiler is straightforward
– Reason for the success story of C
Programming Using C: Choice of High Performance
Tensor Flow lower level optimizations
Edge devices: Coral provides on-device AI for both
prototyping and production projects. It’s a platform
of hardware components, software tools, and pre-
compiled machine learning models, allowing you
to create local AI in any form-factor.
Golden age of computer architecture:
https://dl.acm.org/doi/10.1145/3282307
Innovations like domain-specific hardware, enhanced
security, open instruction sets (RISC-V), and agile chip
development will lead the way.
Example: Operating System Linux in C
› Started in 1991 by Linus
Torvalds
› Linus’ UNIX -> Linux
› Kernel, i.e., core of the
operating system.
› To complete distribution, GNU
tools were used.
› In 1992 the first distributions
emerged.
› Now we have numerous
devices running Linux
– Smartphones, routers, …
› C is the language of choice
– HW Indepdence & Performance
Example: Python written in C
› Python is a scriptinglanguage.
› Was released in 2000; has been spreading rapidly because ease of use.
› Comprises several programmingparadigms
– Imperative
– Object-oriented
– Functional
› Easy tolearn
› Standard reference implementation
is written in C.
Guido van Rossum
Example: Apache Web-Server
› Apache Web-serveris
back-bone of the
internet
› Initially released1995
› surpass the 100million
website milestone in
2009
› Runs widely on
Windows, Unix, Mac,
…
› Written inC
C-Language (cont’)
› C-Programs consists of two languagecomponents
– Preprocessing Language
– C-Language
› PreprocessingLanguage
– Text-macro language
– Definition of macros
– Include files
– Conditional compilation
Java to C
› Differences
– Control flow structures are the same
– esp. before Java 1.4
– References are called “pointers” in C
– No garbage collection
– Programmer is responsible for allocating and freeing memory
– No classes or objects
› A C-program consists of a set of files containing:
– global variables
– function definitions
– “main” is the first function invoked
– functions have local variables
Java
/* This program prints “Hello world.” on a line and exits
*/
public class HelloWorld
{
public static void main (String args[])
{
System.out.println (“Hello world.”);
}
}
The most known C-Program
(int argc, char **argv)
#include
int main
{
printf(“Hello World!\n”);
return 0;
}
› Prints “Hello world!” on standard output
› Does not read from standard input
› Variable argc stores number of arguments
› Variable argv pointers to arguments
int main(int argc, char **argv)
{
int ftemp; /* the fahrenheit temperature */
printf(“Please enter a fahrenheit temperature”);
is %d centigrade”,
(ftemp – 32) * 5 /
ftemp,
9);
scanf(“%d”, &ftemp);
printf(“%d fahrenheit
return 0;
}
Running C Code
› Create a program text in a file whose name has the suffix “.c”
› Compile the program using the command gcc
– gcc hello.c –o hello
– gcc hello.c
› Use all those compiler flags
› Run the program by typing the name of the object file
produced by the compiler. (The default is a.out.)
› ./hello
› ./a.out
Java vs C
Philosophical differences
› C closer to underlyingmachine
› C has simple memory model
– pointers, bit-level operators
– arrays very close to memory model
› C assume programmer knows best
› Java object-oriented v Cprocedural
– No object
– No polymorphism
– No inheritance
Strong similarities
› Blockstructured
› Most controlstructures
– if, else, while, do … while, switch, for (mostly),
– break, continue (no labels in C)
› Arrays
› Operators (mainly the same)
› Basic data types (mainly similar)
More differences – preprocessor
› C macros(#define)
› C has declaration for variables and functions,
often in header files that are included
› conditional compilation (#if, #ifdef, #ifndef,
#else, #elif, etc.)
#define N 1000
//add.h
Int add(int a, int b);
//add.c
#include “add.h”
Int add(int a, int b) {
return a + b
}
#include
#define x 10
int main()
{
#ifdef x
printf(“hello\n”); // this is compiled
as x is defined
#else
printf(“bye\n”); // this isn’t
compiled
#endif
return 0;
}
Arrays and memory
› Arrays can be handled withpointers
› Arrays can be created and initializedin declaration
› C strings are just arrays (withtermination character)
› sizeofoperator
› create dynamic data structures withmalloc()
› C allows declarations only at blockstart (C89 standard)
C99 Standard
1. Will compiler report errors?
2. What the printout will be like?
0:
some string
1: !
some string
2: ”
some string
3: #
some string
4: $
some string
5: %
some string
6: &
some string
7: ‘
some string
8: (
some string
9: )
some string
ASCII: American Standard Code for Information
Interchange
Summary
› C and Java have some similarities
– syntax, control structures
› but some deep differences
– Java is OO, C much closer to the hardware
› C is higher performance than Java
› C is widely used for embedded systems, operating
systems, etc.
› C has evolved into OO forms (Objective C, C++)
Functions in C
A function consists of
– A function declaration:
– Name of function,
– Return type of function,
– Parameter list and their types
– Followed by a function body:
– Local variables & control flow
int foo(float f1, char c2)
…..
int foo(float f1, char c2)
{
int x = 0;
…
return x;
}
Functions in C
› External or forward function declarations do not have a
function body, just a semicolon
– parameter types are specified without variable names
› A function with a given name can only be defined once
› If no return value exists for a function, use the type void
› If no parameters exist use, use type void
int foo(float, char);
void foo(….) { ….}
void foo(void) { ….}
extern int foo(float, char);
Functions in C
› Functions with arbitrary numbers ofparameters
are possible
› In this case, a special interface is required for
querying values of parameters
– Lookup the va_args interface
– At least one fixed parameter in the function is necessary
– Function call is simple
int printf(const char *format, …)
printf(“%d, %f”, 10, 10.5);
Example: using va_arg interface
Example: Function
› Compute factorial n!
int factorial (int n)
{
int result;
if (n > 1 )
{
result = n * factorial(n-1);
}
else
{
result = 1;
}
return result;
}
local variable
function declaration
control flow
Function Example: Factorial (recursive vs iterative)
// C program to find factorial of given number
#include
// Function to find factorial of given number
unsigned int factorial(unsigned int n)
{
if (n == 0)
return 1;
return n * factorial(n – 1);
}
// Driver code
int main()
{
int num = 5;
printf(“Factorial of %d is %d”,
num, factorial(num));
return 0;
}
#include
// Function to find factorial of given number
unsigned int factorial(unsigned int n)
{
int res = 1, i;
for (i = 2; i <= n; i++)
res *= i;
return res;
}
// Driver code
int main()
{
int num = 5;
printf("Factorial of %d is %d",
num, factorial(num));
return 0;
}
Control-structures in C
› Mostly the same as inJava
› statements are terminated by a semicolon; the null statement isallowed.
› A statement can be a sequence of statements inside a block
{
}
Control-structures in C
› if statements:
› while statements:
if (
If (
else
while (
do
while (
Control-structures in C
› for statement:
for (
Control-structures in C
› for statement example:
for ( x = 0; x < 100; x++)
counter[x] = x;
Control-structures in C
› return, break and continue statements:
› return will return to the calling function, optionally returning avalue.
› break ends the loop immediately when it is encountered.
› continue skips the current iteration of the loop and continues with the next
iteration.
return
break;
continue;
Control-structures in C
› switch statement:
switch(…)
{
case
case …: …
default: …
}
Switch Statement Example
// Following is a simple C program
// to demonstrate syntax of switch.
#include
int main()
{
int x = 2;
switch (x)
{
case 1: printf(“Choice is 1”);
break;
case 2: printf(“Choice is 2”);
break;
case 3: printf(“Choice is 3”);
break;
default: printf(“Choice other than 1, 2 and 3”);
break;
}
return 0;
}
C modules
› Programs consist of “modules”
– A module is a file, i.e., hello.c
› Modules consist of
– Function declarations
– Function definitions
– Global variables
› Modules are translated to object files
› Object files are linked by linker with other object files and
standard libraries
C file or module
› A module can refer to global variables and functions of other modules
– use the extern qualifier for global variables
› Symbols can only be defined in one module
› Data structures definitions and declarations, macro definitions and external
function declarations are found in modules
– These are commonly found in header files
#include
#include
int global1;
int foo(int x,int y)
{
return x + y;
}
#include
#include
extern int global1;
extern int foo(int x,int y);
int foo2(int x,int y)
{
return foo(x,y)+global1;
}
Module example
extern int foo();
foo.c
int foo()
{
printf (“hello from foo\n”);
return 0;
}
foo.h
Module example
}
extern int foo();
int main(int argc, char **argv)
{
foo();
return 0;
}
foo.c
int foo()
{
printf (“hello from foo\n”);
return 0;
foo.h
sample.c
#include “foo.h”
Input/Output functions
› Basic Input: int getchar(void);
– reads from standard input next character
– returns -1 (defined as the symbol EOF) if end of input
reached
› Basic Output: void putchar(int c);
– Write a character (represented as an integer) to standard
output
› getchar/putchar are very simple
printf()-function
› printf()-function writes to standardoutput:
– Strings
– variables of primitive a data-type
› Returnvalue:
– Number of printed characters
› Arguments
– First argument is a format string
– Followed my an arbitrary number of parameters depending on format string
› Example:
printf(“%d %f\n”, 10, 10.5);
– Output: 10 10.5
– %d print an integer followed later as a parameter
– %f print a float followed later as a parameter
– \n means print new line
int printf(const char *format, …);
Format string codes for printf
Code Description
%c Character
%d Integer
%u Unsigned integer
%f, %g, %e Double floating point
number
%x Hexadecimal
%ld long
%.2f Print floating point numbers
with two decimal points
%s String
%p Pointer
%% Print %
scanf()-function
› scanf()-function reads from standard input:
– Values of primitive data-type and strings
› Return value:
– Number of successfully read items
› Argument
– First argument is a format string
– Followed my an arbitrary number of parameters depending on format string
– Parameters must be pointers – not values
› Example:
– Read an integer and store it in x
– Read a float and store it in f
– Same format string as in scanf
int scanf(const char *format, …);
int x;
float f;
scanf(“%d %f”, &x, &f);
scanf example
Simple variables
› C has a number of simple data types
– float, int, char etc
– each implies an interpretation of the bit pattern stored in the
memory.
› Declarations label and reserve memory:
int counter;
› Initialization or assignment specifies content:
int counter = 0;
counter = 0;
reserve memory for an integer and call it
“counter”
C- Data Types
Number converter (binary, decimal, hexadecimal):
http://easyonlineconverter.com/converters/dec-to-bin-to-hex-converter.html
sizeof(type) is your best friend!
Example: Detect Integer Overflow
CHAR_BIT : 8
CHAR_MAX : 127
CHAR_MIN : -128
INT_MAX : 2147483647
INT_MIN : -2147483648
LONG_MAX : 9223372036854775807
LONG_MIN : -9223372036854775808
SCHAR_MAX : 127
SCHAR_MIN : -128
SHRT_MAX : 32767
SHRT_MIN : -32768
UCHAR_MAX : 255
UINT_MAX : 4294967295
ULONG_MAX : 18446744073709551615
USHRT_MAX : 65535
0 0 0 1 0 1 1 0 0 1 0 0 0 1 0 0 0 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 1 0
0 0 1 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 1 0 1 0 1 1 1 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1
1 0 0 1 0 1 0 0 1 1 0 0 1 1 0 0 0 0 1 0 1 1 1 1 0 0 1 0 1 0 0 1 0 1 0 0 0 1 1 1
Memory
1 0 0 1 0 1 0 0 1 1 0 0 1 1 0 0 0 0 1 0 1 1 1 1 0 0 1 0 1 0 0 1 0 1 0 0 0 1 1 1
0 0 1 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 1 0 1 0 1 1 1 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1
0 0 0 1 0 1 1 0 0 1 0 0 0 1 0 0 0 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 1 0
Memory
char a;
1 0 0 1 0 1 0 0 1 1 0 0 1 1 0 0 0 0 1 0 1 1 1 1 0 0 1 0 1 0 0 1 0 1 0 0 0 1 1 1
0 0 1 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 0 0 1 0 0 1 0 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1
0 0 0 1 0 1 1 0 0 1 0 0 0 1 0 0 0 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 1 0
Memory
char a;
a = ‘$’;
Arrays
› Arrays are indexed collections of the sametype
› Declaration of anarray:
int counters[MAX];
char alphabet[26];
› Initialisation of anarray:
for (i = 0; i < MAX; i++)
counters[i] = i;
0 0 0 1 0 1 1 0 0 1 0 0 0 1 0 0 0 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 1 0
0 0 1 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 1 0 1 0 1 1 1 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1
1 0 0 1 0 1 0 0 1 1 0 0 1 1 0 0 0 0 1 0 1 1 1 1 0 0 1 0 1 0 0 1 0 1 0 0 0 1 1 1
Memory
0 1 0 0 0 0 1 000 1 0 0 0 0 1
char ch[2];
0 0 0 1 0 1 1 0 0 1 0 0 0 1 0 0 0 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 1 0
0 0 1 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 1 0 1 0 1 1 1 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1
1 0 0 1 0 1 0 0 1 1 0 0 1 1 0 0 0 0 1 0 1 1 1 1 0 0 1 0 1 0 0 1 0 1 0 0 0 1 1 1
“ch[0]”
Memory
“ch[1]”
0 1 0 0 0 0 1 0
char ch[2];
printf(”%c\n”, ch[1]);
0 0 0 1 0 1 1 0 0 1 0 0 0 1 0 0 0 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 1 0
0 0 1 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 1 0 1 0 1 1 1 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1
1 0 0 1 0 1 0 0 1 1 0 0 1 1 0 0 0 0 1 0 1 1 1 1 0 0 1 0 1 0 0 1 0 1 0 0 0 1 1 1
“ch[0]”
Memory
“ch[1]”
char ch[2];
printf(”%c\n”, ch[1]);
“ch[0]”
0 0 0 1 0 1 1 0 0 1 0 0 0 1 0 0 0 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 1 0
0 0 1 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 1 0 1 0 1 1 1 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1
1 0 0 1 0 1 0 0 1 1 0 0 1 1 0 0 0 0 1 0 1 1 1 1 0 0 1 0 1 0 0 1 0 1 0 0 0 1 1 1
Output of random data
Memory
“ch[1]”
1 0 1 1 1 1 0 0 1 0 1 0 0 1 0 1
“ch[0]”
0 0 0 1 0 1 1 0 0 1 0 0 0 1 0 0 0 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 1 0
0 0 1 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 1 0 1 0 1 1 1 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1
1 0 0 1 0 1 0 0 1 1 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0 1 1 1
Output of random data
Memory
“ch[1]”
char ch[2];
printf(”%c\n”, ch[1]);
ch[0] = ’A’;
ch[1] = ’B’;
1 0 1 1 1 1 0 0 1 0 1 0 0 1 0 1
“ch[0]”
AB
Output of random data
0 0 0 1 0 1 1 0 0 1 0 0 0 1 0 0 0 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 1 0
0 0 1 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 1 0 1 0 1 1 1 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1
1 0 0 1 0 1 0 0 1 1 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0 1 1 1
Output of initialised data
Memory
“ch[1]”
char ch[2];
printf(”%c\n”, ch[1]);
ch[0] = ’A’;
ch[1] = ’B’;
printf(”%c%c\n”, ch[0], ch[1]);
Strings
› Strings may be initialised at the time ofdeclaration
using an “array-like” notational convenience:
char myHobby[] = ”rowing”;
The compiler can determine the required size
by counting characters, so the array size is
optional. A larger size may be specified.
Strings
› Strings resemble an array ofcharacters.
› However, in C, all strings areNULL-terminated.
Note: NULL is the binary value 0 (denoted ‘\0’),
not the ASCII representation of the character 0.
char myHobby[] = ”rowing”;
’r’ ’o’ ’w’ ’i’ ’n’ ’g’’\0’
1 0 0 1 0 1 0 0 1 1 0 0 1 1 0 0 0 0 1 0 1 1 1 1 0 0 1 0 1 0 0 1 0 1 0 0 0 1 1 1
0 0 1 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 1 0 1 0 1 1 1 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1
0 0 0 1 0 1 1 0 0 1 0 0 0 1 0 0 0 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 1 0
char str[] = ”A”;
printf(”%s\n”, str);
“str”
0 1 0 0 0 0 0 1
A
Memory
0 0 0 0 0 0 0 0
sizeof operator
› Not all h/w architectures are the same
- different sizes for basic types
› C specification does not dictate exactly how many bytes an
int will be
› sizeof operator returns the number of bytes used to
represent the given type or expression
- sizeof( char )
- sizeof( int )
- sizeof( float * )
- sizeof ( 1 )
sizeof operator
› Not all h/w architectures are the same
- different sizes for basic types
› C specification does not dictate exactly how many bytes an
int will be
› sizeof operator returns the number of bytes used to
represent the given type or expression.
- sizeof( char )
- sizeof( int ), sizeof( double )
- sizeof( float * )
- sizeof ( 1 ), sizeof ( 1/2 ), sizeof (1.0 / 2.0)
- sizeof( p ) ????
sizeof
› Special case for p, what is it?
- char p;
- char *p;
- char p[8];
› But…
- char msg[100]; // 100
- char *p = msg; // 8
- char msg2[] = “hello message”; // 14
- char *p = msg2; // 8
- char *p = “program has ended”; // 8
› sizeof needs to be used carefully
Less familiar types
› The types char will support the value range from
CHAR_MIN to CHAR_MAX as defined in file
– #define CHAR_MAX 127 /* max value for a char */
– #define CHAR_MIN (-128) /* min value for a char */
› Most C implementations default types as signed values, but
a warning that you should not assume this.
› unsigned and signed enforce the sign usage
– char ch;
– signed char ch;
– unsigned char ch;
– unsigned int total;
#include
int main()
{
printf(“%lu”, sizeof(void));
return 0;
}
#include
int main()
{
printf(“%lu”,sizeof(void *));
return 0;
}
Void Pointer size
Since NULL is typically defined as ((void*)0), let us discuss a little bit about void type as well. As per C11
standard clause 6.2.5, “The void type comprises an empty set of values; it is an incomplete object type that
cannot be completed”. Even C11 clause 6.5.3.4 mentions that “The sizeof operator shall not be applied to an
expression that has function type or an incomplete type, to the parenthesized name of such a type, or to an
expression that designates a bit-field member.” Basically, it means that void is an incomplete type whose
size doesn’t make any sense in C programs but implementations (such as gcc) can choose sizeof(void) as 1
so that the flat memory pointed by void pointer can be viewed as untyped memory i.e. a sequence of bytes.
But the output of the following needn’t to same on all platforms.
On gcc, the above would output 1. What about sizeof(void *)? Here C11 has mentioned
guidelines. From clause 6.2.5, “A pointer to void shall have the same representation
and alignment requirements as a pointer to a character type”. That’s why the output of
the following would be same as any pointer size on a machine.
Less familiar const
› constprevents the value being modified
– const char *fileheader = “P1”
– fileheader[1] = ‘3’;
› It can be used to help avoid arbitrary changes tomemory
› The value constprotects depends where it appears
– char * const fileheader = “P1”
– fileheader = “P3”;
› Reading right to left:
– Is an address, points to a char, that is constant
– Is an address, that is constant
Illegal: change of address value
Illegal: change of char value
Less familiar const
› constprevents the value being modified
– const char *fileheader = “P1”
– fileheader[1] = ‘3’;
› It can be used to help avoid arbitrary changes tomemory
› The value constprotects depends where it appears
– char * const fileheader = “P1”
– fileheader = “P3”;
› You can cast if you know if the memory iswritable
Illegal: change of address value
Illegal: change of char value
char fileheader[] = {‘P’, ‘1’};
const char *dataptr = (char*)fileheader;
char *p = (char*)dataptr;
p[1] = ‘3’;
writable
Non-writable
Floating point types
› Exact bit representation unknown, usually IEEE754
› Generally, floating point number x is defined as:
› s sign
› b base of exponent (e.g. 2, 10,16)
› e exponent
› p precision
› fk nonnegative integer less than b
+0
+ve / 0 = +infinite
NaN (not a number)
-0
-ve / 0 = -infinite
Zero exponents…
FACULTY OF
ENGINEERING
Variable Scope and Lifetime
Scope and Lifetime of Variables in C
Declaration vs. Definition
• A declaration tells the compiler the type of a
variable, object or function.
• A definition allocates memory for a variable
or object and is the implementation of a
function.
• Multiple declarations are allowed, but only
one definition.
Scope and Lifetime of Variables in C
Declaration vs. Definition:
//add.h
Int add(int a, int b);
//add.c
#include “add.h”
Int add(int a, int b) {
return a + b
}
Scope and Lifetime of Variables in C
Scope & Lifetime:
• The scope of a declaration is the part of the
program for which the declaration is in
effect.
• C/C++ use lexical scoping (aka. static
scope).
• The lifetime of a variable or object is the
time period in which the variable/object has
valid memory.
• Lifetime is also called “allocation method” or
“storage duration.”
Scope and Lifetime of Variables in C
Lifetime:
• Static: The memory for static objects is allocated at
compile/link time. It’s lifetime is the entire duration of the
program’s execution.
Scope and Lifetime of Variables in C
Lifetime:
• Static: The memory for static objects is allocated at
compile/link time. It’s lifetime is the entire duration of the
program’s execution.
• Automatic: An automatic variable has a lifetime that begins
when program execution enters the function or statement
block or compound and ends when execution leaves the
block. Automatic variables are stored in a “function call
stack”.
Stack Overflow (I)
1. If we declare large number of local variables or declare an array or matrix or any
higher dimensional array of large size can result in overflow of stack.
// C program to demonstrate stack overflow
// by allocating a large local memory
#include
int main() {
// Creating a matrix of size 10^5 x 10^5
// which may result in stack overflow.
int mat[100000][100000];
}
Stack Overflow (II)
// C program to demonstrate stack overflow
// by creating a non-terminating recursive
// function.
#include
void fun(int x)
{
if (x == 1)
return;
x = 6;
fun(x);
}
int main()
{
int x = 5;
fun(x);
}
2. If function recursively call itself infinite times then the stack is unable to store large
number of local variables used by every function call and will result in overflow of stack.
Program Crashing!!!
Core Dump/Segmentation Fault
Core Dump/Segmentation fault is a specific kind of error caused by accessing memory that
“does not belong to you.”
•When a piece of code tries to do read and write operation in a read only location in memory
or freed block of memory, it is known as core dump.
•It is an error indicating memory corruption.
Six Main Ways:
1. Modifying a string literal (writing to read-only memory)
2. Accessing an address that is freed (not allowed in compiler)
3. Accessing out of array index bounds
4. Improper use of scanf() (input fetched from STDIN is placed in invalid memory,
causing memory corruption)
5. Stack Overflow
6. Dereferencing uninitialized pointer (A pointer must point to valid memory
before accessing it).
Scope and Lifetime of Variables in C
Lifetime:
• Static: The memory for static objects is allocated at
compile/link time. It’s lifetime is the entire duration of the
program’s execution.
• Automatic: An automatic variable has a lifetime that begins
when program execution enters the function or statement
block or compound and ends when execution leaves the
block. Automatic variables are stored in a “function call
stack”.
• Dynamic: The lifetime of a dynamic object begins when
memory is allocated for the object (e.g., by a call to
malloc()) and ends when memory is deallocated (e.g., by a
call to free() or using delete). Dynamic objects are stored
in “the heap”.
Scope and Lifetime of Variables in C
int cnt_even = 0;
int *cnt_odd = NULL;
int count_even_and_odd(int arr[], int len) {
static int cnt_call_times = 0;
cnt_call_times++;
if (cnt_odd == NULL) {
cnt_odd = malloc(sizeof(int)); *cnt_odd = 0;
}
int i;
for (i = 0; i < len; i++) { if (arr[i] % 2 == 0) cnt_even++; else (*cnt_odd)++; } return cnt_call_times; } A very simple program for counting even and odd number count. Return how many time the function was called. Scope and Lifetime of Variables in C int cnt_even = 0; int *cnt_odd = NULL; int count_even_and_odd(int arr[], int len) { static int cnt_call_times = 0; cnt_call_times++; if (cnt_odd == NULL) { cnt_odd = malloc(sizeof(int)); *cnt_odd = 0; } int i; for (i = 0; i < len; i++) { if (arr[i] % 2 == 0) cnt_even++; else (*cnt_odd)++; } return cnt_call_times; } A very simple program for counting even and odd number count. Return how many time the function was called. Lifetime: Static Scope and Lifetime of Variables in C int cnt_even = 0; int *cnt_odd = NULL; int count_even_and_odd(int arr[], int len) { static int cnt_call_times = 0; cnt_call_times++; if (cnt_odd == NULL) { cnt_odd = malloc(sizeof(int)); *cnt_odd = 0; } int i; for (i = 0; i < len; i++) { if (arr[i] % 2 == 0) cnt_even++; else (*cnt_odd)++; } return cnt_call_times; } A very simple program for counting even and odd number count. Return how many time the function was called. Lifetime: Static Dymamic Scope and Lifetime of Variables in C int cnt_even = 0; int *cnt_odd = NULL; int count_even_and_odd(int arr[], int len) { static int cnt_call_times = 0; cnt_call_times++; if (cnt_odd == NULL) { cnt_odd = malloc(sizeof(int)); *cnt_odd = 0; } int i; for (i = 0; i < len; i++) { if (arr[i] % 2 == 0) cnt_even++; else (*cnt_odd)++; } return cnt_call_times; } A very simple program for counting even and odd number count. Return how many time the function was called. Lifetime: Static Dymamic Automatic Static Variables • All the static variables that do not have an explicit initialization or are initialized to zero are stored in the uninitialized data segment( also known as the BSS segment). In computer programming, the name .bss or bss is used by many compilers and linkers for the portion of an object file or executable containing statically-allocated variables that are not explicitly initialized to any value. It is often referred to as the "bss section" or "bss segment". • Compared to this, the static variables that are initialized are stored in the initialized data segment. • Local statics may look useful, however they cause major problems when trying to port code to a multi-task/multi-threading environment, and should generally be avoided where possible. https://en.wikipedia.org/wiki/Computer_programming https://en.wikipedia.org/wiki/Compiler https://en.wikipedia.org/wiki/Linker_(computing) https://en.wikipedia.org/wiki/Object_file https://en.wikipedia.org/wiki/Static_variable •global variables -------> data
•static variables ——-> data
•constant data types —–> code (ready-only) and/or data. Consider string literals for a
situation when a constant itself would be stored in the data segment, and references to it
would be embedded in the code
•local variables(declared and defined in functions) ——–> stack
•variables declared and defined in main function —–> stack
•pointers(ex: char *arr, int *arr) ——-> data or stack, depending on the context. C
lets you declare a global or a static pointer, in which case the pointer itself would end
up in the data segment.
•dynamically allocated space (using malloc, calloc, realloc) ——–> heap
It is worth mentioning that “stack” is officially called “automatic storage class”.
This shows the typical layout of a simple
computer’s program memory with the text,
various data, and stack and heap sections.
Scope and Lifetime of Variables in C
Scope:
• The scope of an object is the part of the program where the
variable can be accessed (i.e. it is visible).
• File scope
• Block scope
• A variable must be declared before it is accessed
• scope of a variable is determined by the placement of its
declaration
Scope and Lifetime of Variables in C
File Scope
• Any variable declared with file scope can be accessed by
any function defined after the declaration
Block Scope
• Block scope is defined by the pairing of the curly braces {
and } . A variable declared within a block can only be
accessed within that block.
int global_a = 0; // File Scope
Int func() {
int local_b = 1; // Block Scope
int i = 10;
while(i–) {
int b; // Block Scope
}
}
Scope and Lifetime of Variables in C
Scope Overlapping:
Rule: An inner scope identifier always hides an outer scope
identifier
int k = 20;
int main()
{
int k = 10;
printf( “In main, k is %d\n”, k);
}
//output: In main, k is 10
FACULTY OF
ENGINEERING
Pointers
Memory
00100010
01010010
00110110
00101010
10100010
01100010
00111010
00100110
11100010
0x100
0x101
0x102
0x103
0x104
0x105
0x106
0x107
0x108
…
address content
Pointers
Memory
Random values initially
00100010
01010010
00110110
00101010
10100010
01100010
00111010
00100110
11100010
0x100
0x101
0x102
0x103
0x104
0x105
0x106
0x107
0x108
…
address content
Pointers
Memory
› a pointer is essentially a variable that
stores a memory address
› we can find out the address of a variable using
the & operator
00100010
01010010
00110110
00101010
10100010
01100010
00111010
00100110
11100010
0x100
0x101
0x102
0x103
0x104
0x105
0x106
0x107
0x108
…
address content
Pointers
Memory
char initial = ‘A’;
char *initp = &initial
&initial is the address of initial
initp is a pointer to initial
00100010
01010010
00110110
00101010
10100010
01100010
00111010
00100110
11100010
0x100
0x101
0x102
0x103
0x104
0x105
0x106
0x107
0x108
…
address content
Pointers
0 0 1 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 1 0 1 0 1 1 1 0 1 0 1 0 1 1
1 1 0 0 1 1 0 0 0 0 1 0 1 1 1 1 0 0 1 0 1 0 0 1 0 1 0 0 0 1 1 1
0 0 0 1 0 1 1 0 0 1 0 0 0 1 0 0 0 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1
0 1 0 0 0 1 1 11 0 0 1 0 1 0 0 1 1 0 0 1 1 0 0 0 0 1 0 1 1 1 1 0 0 1 0 1 0 0 1
variable name: “count”
address of count: 0x1000 = 4,096
0 0 0 1 0 1 1 0 0 1 0 0 0 1 0 0 0 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 1 0
0 0 1 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 1 0 1 0 1 1 1 0 1 0 1 0 1 1 0 0 0 0 1 0 0 1
1 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
Clearly, the value of a pointer can
only be determined at run-time.
Somewhere in memory…
Somewhere else in memory…
Label: “ptr”
int count;
int *ptr;
count = 2;
ptr = &count;
printf(”%d\n”, count);
printf(”%d\n”, *ptr);
printf(”%d\n”, &count);
printf(”%d\n”, ptr);
2
2
4096
4096
Label: “count”
Pointers (notation)
› Pointer operators:
– address operator, ‘&’
– indirection operator, ‘*’
Note that these operators are “overloaded”, that is they have
more than one meaning.
– ‘&’ is also used in C as the bitwise ‘AND’ operator
– ‘*’ is also used in C as the multiplication operator
Pointers (notation)
› The indirection operator, ‘*’, is used in a variable
declaration to declare a “pointer to a variable of the
specified type”:
int * countp; /* pointer to an integer */
Type is “a pointer to an integer”
Variable name, “countp”
What do the following
mean?
float * amt;
int ** tricky;
Answers:
A pointer (labeled “amt”) to
a float.
A pointer (labeled “tricky”)
to a pointer to an int.
Pointers (notation)
…prints ‘2’ to standard output.
› The indirection operator, ‘*’, is used to “unravel” the
indirection:
countp points to an integer variable that contains the value 2.
Then…
2
printf(”%d”, *countp);
countp
Unravel the
indirection
What is output in the following?
printf(”%d”, count);
17
printf(”%d”, *countp);
17
printf(”%d”, countp);
Don’t know… but it will be
the address of count.
Why?
17
countp
count
› The address operator, ‘&’, is used to accessthe
address of a variable.
›This completes the picture! A pointer can be
assigned the address of a variable simply:
int * countp = &count;
Declare “a pointer to an integer” called countp
Assign countp the address of count.
An example of the the address operator in action…
Receiving an integer from standard input:
int age;
scanf(”%d”, &age);
This argument is required by scanf()
to be a pointer. Since we are using
a simple integer, age, we pass it’s
address.
Examples
Use of pointer notation to manipulate arrays…
char msg[] = ”Hello!”;
char *str = &msg[0];
OR:
char *str = msg;
’H’ ’e’ ’l’ ’l’ ’o’ ’!’ ’/0’
Pointers and arrays
’H’ ’e’ ’l’ ’l’ ’o’ ’!’ ’/0’
msg[0]
str[0]
*str
msg[1]
str[1]
*(str+1)
Pointer notation leads to some (intimidating?) shortcuts as
part of the C idiom.
Moving through a string:
while (*str != ’\0’)
str++;
’H’ ’e’ ’l’ ’l’ ’o’ ’!’ ’/0’
The previous example may exploit the fact that C
treats ‘0’ as FALSE:
while (*str)
str++;
’H’ ’e’ ’l’ ’l’ ’o’ ’!’ ’/0’
Examples
› Some mathematical operations are moreconvenient
using pointers
– e.g., array operations
› However, we have only looked at static data. Pointers
are essential in dealing with dynamic data structures.
› Imagine you are writing a texteditor.
– You could estimate the largest line-length and create arrays of
that size (problematic).
– Or you could dynamically allocate memory as needed, using
pointers.
›What is the value held by p? and how much
memory is used by p (in bytes)?
› int p;
› char p;
› void foo( int *p )
› char *p;
› char **p;
›What is the value held by p? and how much
memory is used by p (in bytes)?
› int p;
› char p;
› void foo( int *p )
› char *p;
› char **p;
› int **p;
› long *p;
› void *p;
› const unsigned long long int * const p;
› bubblebobble ************p;
› char *p
– Address to a single char value
– Address to a single char value that is the first in an array
› char *argv[]
– Array of “the type” with unknown length
– Type is char *
› char **argv
– * Address to the first element to an array of type char *
– Then, each element in * is an…
– * address to the first element to an array of type char
char argv[][3]; // oh no!
› Interpretations of int **data;
1. Pointer to pointer to single int value
2. Array of addresses that point to a single int
3. Address that points to one array of int values
4. Array of addresses that point to arrays of int values
Pointer interpretation
› Interpretations of int **data;
1. Pointer to pointer to single int value
2. Array of addresses that point to a single int
3. Address that points to one array of int values
4. Array of addresses that point to arrays of int values
› Thinking about each * as an array:
1. Array size ==1, Array size ==1
2. Array size >=1, Array size == 1
3. Array size ==1, Array size >= 1
4. Array size >=1, Array size >= 1
Pointer interpretation
› When you call a function in Java, compare passing a
primitive type and Object type.
› You may have heard:
– Pass by value
– Pass by reference
What is the meaning of this in C?
› void has no size, but sizeof(void*) is the size of an address
› Pointers are unsigned numbers, why?
Pointer comments
0x0100 0x0104 0x0105
› int *p = NULL;
› int x[4];
› p = x;
x = 0x0100
0x0101 0x0101 0x0102 0x0103
0 0 0 17
0x0106 0x0107 0x0108 0x0109 0x010A 0x010B 0x010C 0x010D 0x010E
*(p + 0) *(p + 1) *(p + 2)
› Seeking to the nth byte from a starting address?
*(p + 3)
Pointer arithmetic
0x0100 0x0104 0x0105
› int *p = NULL;
› int x[4];
› p = x;
x = 0x0100
0x0101 0x0101 0x0102 0x0103
0 0 0 17
0x0106 0x0107 0x0108 0x0109 0x010A 0x010B 0x010C 0x010D 0x010E
*(p + 0) *(p + 1) *(p + 2) *(p + 3)
› Seeking to the nth byte from a starting address?
void *get_address( sometype *data , int n) {
unsigned char *ptr = (unsigned char*)data;
return (void*)(ptr + n);
}
Pointer arithmetic
Q1
Assume that an int variable takes 4 bytes and a char variable takes 1 byte
(A) Number of elements between two pointer are: 5.
Number of bytes between two pointers are: 20
(B) Number of elements between two pointer are: 20.
Number of bytes between two pointers are: 20
(C) Number of elements between two pointer are: 5.
Number of bytes between two pointers are: 5
(D) Compiler Error
(E) Runtime Error
Q2
(A) Compiler Error
(B) Garbage Value
(C) Runtime Error
(D) G
Q3
(A) 10 20 30 40
(B) Machine Dependent
(C) 10 20
(D) Northing
Q4
Assuming 32-bit machine:
(A) sizeof arri[] = 3 sizeof ptri = 4 sizeof arrc[] = 3 sizeof ptrc = 4
(B) sizeof arri[] = 12 sizeof ptri = 4 sizeof arrc[] = 3 sizeof ptrc = 1
(C) sizeof arri[] = 3 sizeof ptri = 4 sizeof arrc[] = 3 sizeof ptrc = 1
(D) sizeof arri[] = 12 sizeof ptri = 4 sizeof arrc[] = 3 sizeof ptrc = 4
Q5
(A) 2 2
(B) 2 1
(C) 0 1
(D) 0 2
Q6
S1: will generate a compilation error
S2: may generate a segmentation fault at runtime depending on the arguments passed
S3: correctly implements the swap procedure for all input pointers referring to integers
stored in memory locations accessible to the process
S4: implements the swap procedure correctly for some but not all valid input pointers
S5: may add or subtract integers and pointers.
(A) S1
(B) S2 and S3
(C) S2 and S4
(D) S2 and S5
Q7
(A) 18
(B) 19
(C) 21
(D) 22
Q8
(A) 12
(B) Compiler Error
(C) Runt Time Error
(D) 0
Q9
(A)
(geeksquiz, geeksforgeeks) (geeksforgeeks, geeksquiz)
(B)
(geeksforgeeks, geeksquiz) (geeksquiz, geeksforgeeks)
(C)
(geeksquiz, geeksforgeeks) (geeksquiz, geeksforgeeks)
(D)
(geeksforgeeks, geeksquiz) (geeksforgeeks, geeksquiz)
Q10
(A) ab
(B) cd
(C) ef
(D) gh
End of Section