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/
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)
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
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 such as
– Objects and Classes
– Templates
– Operator/Function overloading
› C++ overcomes this and is a successor of C
› Writing a non-optimizing C-Compiler is straightforward
– Reason for the success story of C
Programming Using C: Choice of High Performance
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.
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.
Tensor Flow lower level optimizations
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 in C
C-Language (cont’)
› C-Programs consists of two languagecomponents – Preprocessing Language
– C-Language
› Preprocessing Language – 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
#include
int main (int argc, char **argv)
{
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”);
scanf(“%d”, &ftemp);
printf(“%d fahrenheit is %d centigrade”, ftemp, (ftemp-32)*5/ 9);
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
› Block structured
› Most control structures
– 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) #define N 1000
› C has declaration for variables and functions,
often in header files that are included
//add.h //add.c
#include “add.h”
Int add(int a, int b); Int add(int a, int b) { return a + b
}
› conditional compilation (#if, #ifdef, #ifndef, #else, #elif, etc.)
#include
int main()
{
#ifdef x printf(“hello\n”);
as x is defined
#else printf(“bye\n”);
compiled
#endif
return 0;
}
// this is compiled
// this isn’t
Arrays and memory
› Arrays can be handled withpointers
› Arrays can be created and initializedin declaration
› C strings are just arrays (withtermination character)
› sizeof operator
› 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
– Afunctiondeclaration:
– Name of function,
– Return type of function,
– Parameter list and their types
int foo(float f1, char c2) …..
int foo(float f1, char c2) {
int x = 0; … return x;
}
– Followed by a function body:
– Local variables & control flow
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);
extern int foo(float, char);
void foo(….) { ….}
void foo(void) { ….}
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)
function declaration
local variable control flow
{
int result; if (n > 1 )
}
{
} else {
result = 1; return result;
}
result = n * factorial(n-1);
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)
{
#include
// Function to find factorial of given number unsigned int factorial(unsigned int n)
{
}
// Driver code int main()
{
// Driver code int main()
{
int num = 5;
printf(“Factorial of %d is %d”,
num, factorial(num)); return 0;
}
if (n == 0)
return 1;
return n * factorial(n – 1);
int res = 1, i;
for (i = 2; i <= n; i++)
res *= i; return res;
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:
If (
else
› while statements:
if (
while (
do
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 a value. › break ends the loop immediately when it is encountered.
› continue skips the current iteration of the loop and continues with the next iteration.
return
continue;
Control-structures in C
› switch statement:
switch(…)
{
case
default: …
}
Switch Statement Example
// Following is a simple C program // to demonstrate syntax of switch. #include
int main()
{
int x = 2; switch (x) {
}
return 0; }
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;
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 – usetheexternqualifierforglobalvariables
› Symbols can only be defined in one module
› Data structures definitions and declarations, macro definitions and external
function declarations are found in modules – Thesearecommonlyfoundinheaderfiles
#include
extern int global1;
extern int foo(int x,int y);
int foo2(int x,int y)
{
return foo(x,y)+global1;
}
#include
int global1;
int foo(int x,int y) {
return x + y; }
Module example
foo.c
int foo() {
printf (“hello from foo\n”);
return 0; }
foo.h extern int foo();
Module example
foo.c
int foo() {
printf (“hello from foo\n”); return 0;
foo.h extern int foo();
}
sample.c #include “foo.h”
int main(int argc, char **argv) {
foo();
return 0; }
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 standard output: – 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
sizeof(type) is your best friend!
Number converter (binary, decimal, hexadecimal): http://easyonlineconverter.com/converters/dec-to-bin-to-hex-converter.html
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
Memory
0
0
1
0
0
0
0
1
0
1
1
1
0
0
0
1
0
1
1
1
0
0
0
0
0
0
1
1
1
1
0
1
0
0
0
0
0
0
1
1
1
1
0
0
0
0
0
0
0
1
0
0
0
0
1
1
1
0
0
0
1
1
1
0
0
1
1
1
1
1
1
1
0
1
0
0
0
0
0
1
1
0
0
0
1
1
1
0
0
0
0
1
0
1
1
1
0
0
0
0
0
1
0
0
0
0
0
0
1
1
0
1
0
1
1
0
1
0
1
1
Memory
00 01 11
char a;
0010110 0110010 0010100
0100010000101011000010010000111 0110010010101011101010110000100 1100110000101111001010010100011
Memory
00 01 11
char a;
a = ‘$’;
0010110 0110010 0010100
0100010000101011000010010000111 0110010010001001001010110000100 1100110000101111001010010100011
Arrays
› Arrays are indexed collections of the same type › Declaration of anarray:
int counters[MAX]; char alphabet[26];
› Initialisation of anarray: for (i = 0; i < MAX; i++)
counters[i] = i;
Memory
0
0
1
0
0
0
0
1
0
1
1
1
0
0
0
1
0
1
1
1
0
0
0
0
0
0
1
1
1
1
0
1
0
0
0
0
0
0
1
1
1
1
0
0
0
0
0
0
0
1
0
0
0
0
1
1
1
0
0
0
1
1
1
0
0
1
1
1
1
1
1
1
0
1
0
0
0
0
0
1
1
0
0
0
1
1
1
0
0
0
0
1
0
1
1
1
0
0
0
0
0
1
0
0
0
0
0
0
1
1
0
1
0
1
1
0
1
0
1
1
Memory
0
0
1
0
0
0
0
1
1
1
0
0
1
1
1
0
0
0
0
0
1
1
1
0
0
0
0
0
1
1
1
1
0
0
0
0
0
0
0
1
0
0 10
01
10
10
10
10
0
0 0
01 10
01
10
0
0
10
01
10 0
0
0
0
1
1
0
1
0
1
1
0
1
0
0
1
0
0
1
0
1
1
0
0
01 01
0 0
1 1
0 0
1 1
1 1
0 1
0 1
0 0
1 1
0 0
0 1
1 1
0 0
00 00
1
1
char ch[2];
“ch[0]”
“ch[1]”
Memory
0
0
0
1
0
1
1
0
0
1
0
0
0
1
0
0
0
0 0
1 1
0 0
1 1
1 1
0 1
0 0
0 0
1 1
0 0
0
1
1
1
0
0
1
0
01 01
0 1
0 1
1 1
0 0
00 00
0
1
0
0
1
1
0
0
1
1
0
0
0
0
1
1
1
1
0
0
0
0
1
1
1
0
0
0
0
1
0
01
0
1
1
1
1
0
0 10 01 10 0 0 0 0 10 01 01 0
0
0
1
0
0
1
0
1
1
1
char ch[2]; printf(”%c\n”, ch[1]);
“ch[0]”
“ch[1]”
Memory
0
0
1
0
0
0
0
1
1
1
0
0
1
1
1
0
0
0
0
0
1
1
1
0
0
0
0
0
1
1
1
1
0
0
0
0
0
0
0
1
0
01
0
1
1
1
1
0
0 0
01
0
1
0
0
1
0
10
0
0
0
1
1
0
1
0
1
1
0
1
0
0
1
0
0
1
0
1
1
0
0
01 01
0 0
1 1
0 0
1 1
1 1
0 1
0 1
0 0
1 1
0 0
0 1
1 1
0 0
00 00
1
1
char ch[2]; printf(”%c\n”, ch[1]);
“ch[0]”
“ch[1]”
Output of random data
Memory
0
0
0
1
0
1
1
0
0
1
0
0
0
1
0
0
0
0 0
1 1
0 0
1 1
1 1
0 1
0 0
0 0
1 1
0 0
0
1
1
1
0
0
1
0
01 01
0 1
0 1
1 1
0 0
00 00
0
1
0
0
1
1
0
0
1
1
0
0
0
0
1
1
1
1
0
0
0
0
1
1
1
0
0
0
0
1
0
0 01
10
01
01
01
01
0
10 01 10 01 0 0 0 0 01 10 01 0
0
0
1
0
0
1
0
1
1
1
char ch[2]; printf(”%c\n”, ch[1]); ch[0] = ’A’;
ch[1] = ’B’;
“ch[0]”
“ch[1]”
Output of random data
Memory
0
0
0
1
0
1
1
0
0
1
0
0
0
1
0
0
0
0 0
1 1
0 0
1 1
1 1
0 1
0 0
0 0
1 1
0 0
0
1
1
1
0
0
1
0
01 01
0 1
0 1
1 1
0 0
00 00
0
1
0
0
1
1
0
0
1
1
0
0
0
0
1
1
1
1
0
0
0
0
1
1
1
0
0
0
0
1
0
0 01
10
01
01
01
01
0
10 01 10 01 0 0 0 0 01 10 01 0
0
0
1
0
0
1
0
1
1
1
char ch[2]; printf(”%c\n”, ch[1]); ch[0] = ’A’;
“ch[0]”
“ch[1]”
ch[1] = ’B’;
printf(”%c%c\n”, ch[0], ch[1]);
Output of random data
AB
Output of initialised data
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’
Memory
00 01 11
0010110 0110010 0010100
0100010000101011000010010000111 0110010010101011101010110000100
1100110000 00011
01 01 01 01 01 01 0 0 10
010010001001
char str[] = ”A”; printf(”%s\n”, str);
“str”
A
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
255 /* max value for an unsigned char */ 127 /* max value for a char */ (-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;
Void Pointer size
#include
int main()
{
printf(“%lu”, sizeof(void)); return 0;
}
#include
int main()
{
printf(“%lu”,sizeof(void *)); return 0;
}
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 to memory
› The value constprotects depends where it appears
– char * const fileheader = “P1”
– fileheader = “P3”; Illegal: change of address value
› Reading right to left:
– Is an address, points to a char, that is constant – Is an address, that is constant
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 to memory
› The value constprotects depends where it appears
– char * const fileheader = “P1”
– fileheader = “P3”; Illegal: change of address value
› You can cast if you know if the memory is writable char fileheader[] = {‘P’, ‘1’};
Illegal: change of char value
Non-writable
writable
const char *dataptr = (char*)fileheader; char *p = (char*)dataptr;
p[1] = ‘3’;
Floating point types
› Exact bit representation unknown, usually IEEE754
› Generally, floating point number xis 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…
Variable Scope and Lifetime
FACULTY OF ENGINEERING
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 //add.c
#include “add.h”
Int add(int a, int b); 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)
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.
// 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);
}
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. Modifyingastringliteral(writingtoread-onlymemory)
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. StackOverflow
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
A very simple program
for counting even and
odd number count.
Return how many time
the function was called.
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; }
Scope and Lifetime of Variables in C
A very simple program
for counting even and
odd number count.
Return how many time
the function was called.
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; }
Lifetime:
Static
Scope and Lifetime of Variables in C
A very simple program
for counting even and
odd number count.
Return how many time
the function was called.
int = 0;
int * = 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; }
cnt_even
cnt_odd
Lifetime:
Static
Dymamic
Scope and Lifetime of Variables in C
A very simple program
for counting even and
odd number count.
Return how many time
the function was called.
int = 0;
int * = 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; }
Lifetime:
Static
Dymamic
cnt_even
cnt_odd
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.
•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
Pointers
FACULTY OF ENGINEERING
Pointers
Memory
address
0x100
0x101
0x102
0x103
0x104
0x105
0x106
0x107
0x108 …
content
00100010
01010010
00110110
00101010
10100010
01100010
00111010
00100110
11100010
Pointers
Memory
address
0x100 0x101 0x102 0x103 0x104 0x105 0x106 0x107
0x108 …
content
00100010
01010010
00110110
00101010
10100010
01100010
00111010
00100110
11100010
Random values initially
Pointers
Memory
address
0x100 0x101 0x102 0x103 0x104 0x105 0x106 0x107
0x108 …
content
00100010
01010010
00110110
00101010
10100010
01100010
00111010
00100110
11100010
› a pointer is essentially a variable that stores a memory address
› we can find out the address of a variable using the & operator
Pointers
Memory
address
0x100 0x101 0x102 0x103 0x104 0x105 0x106 0x107
0x108 …
content
char initial = ‘A’; char *initp = &initial
00100010
01010010
00110110
00101010
10100010
01100010
00111010
00100110
11100010
&initial is the address of initial initp is a pointer to initial
0Somewhere in memory… 1
Somewh
int count;
int *ptr;
count = 2;
ptr = &count;
printf(”%d\n”, count); printf(”%d\n”, *ptr);
printf(”%d\n”, &count); printf(”%d\n”, ptr);
Label: “ptr”
0
0
0
0
0
01
0
1
01
1
0
0
0
1
0
1
1
01
0
0
0
0
0
0
1
ere else in memory…
Label: “count”
1
01
1
0
01
0
0
0
0
0
0
1
1
01
1
0
0
0
0
0
0
0
01
0
0
0
0
1
01
1
0
10
0
1
01
1
0
0
1
1
01
1
1
01
1
0
01
0
0
0
0
0
01
1
0
0
0
1
01
1
0
0
0
0
01
0
10
01
10
0
0
0
1
0
0
0
0
0
0
1
1
0
1
0
1
1
0
1
0
1
1
0
0
1
0
0
0
0
1
0
1
1
1
0
0
0
1
0
1
1
1
0
00 00
0 01
1 1
01
0 1
0
0 0
0
0 0
01
1 1
01
0 0
0
0 0
0
0
1
0
0
0
0
1
1
01
0
0
0
1
1
01
0
0
01
1
1
01
1
1
01
0
1
0
0
0
0
0
1
01
0
0
0
1
1
01
0
0
0
0
1
0
1
1
01
0
0
0
0
0
01
0
0
0
0
0
0
1
1
0
1
0
01
1
0
1
0
1
01 address of count: 0x1000 = 4,096
Clearly, the value of a pointer can only be determined at run-time.
2
2 4096 4096
variable name: “count”
Pointers (notation)
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
› 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 */
Variable name, “countp” Type is “a pointer to an integer”
Pointers (notation)
What do the following mean?
float * amt;
Answers:
A pointer (labeled “amt”) to
a float.
A pointer (labeled “tricky”) to a pointer to an int.
int ** tricky;
› The indirection operator, ‘*’, is used to “unravel” the indirection:
countp points to an integer variable that contains the value 2. Then…
printf(”%d”, *countp); …prints ‘2’ to standard output.
Unravel the indirection
countp
2
What is output in the following?
printf(”%d”, count);
17 17
printf(”%d”, *countp); 17
printf(”%d”, countp);
Don’t know… but it will be the address of count. Why?
count
countp
› 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:
Declare “a pointer to an integer” called countp int * countp = &count;
Assign countp the address of count.
Examples
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.
Pointers and arrays
Use of pointer notation to manipulate arrays…
char msg[] = ”Hello!”; char *str = &msg[0];
OR:
char *str = msg;
’H’ ’e’ ’l’ ’l’ ’o’ ’!’ ’/0’
msg[0] str[0] *str
’H’ ’e’ ’l’ ’l’ ’o’ ’!’ ’/0’
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’
Examples
The previous example may exploit the fact that C treats ‘0’ as FALSE:
while (*str) str++;
’H’ ’e’ ’l’ ’l’ ’o’ ’!’ ’/0’
› 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!
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
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 comments
› 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 arithmetic
› int *p = NULL; › int x[4];
› p = x;
x = 0x0100
0x0100 0x0101 0x0101 0x0102 0x0103 0x0104 0x0105 0x0106 0x0107 0x0108 0x0109 0x010A 0x010B 0x010C 0x010D 0x010E
0 0 0 17
*(p + 0) *(p + 1) *(p + 2) *(p + 3) › Seeking to the nth byte from a starting address?
Pointer arithmetic
› int *p = NULL; › int x[4];
› p = x;
x = 0x0100
0x0100 0x0101 0x0101 0x0102 0x0103 0x0104 0x0105 0x0106 0x0107 0x0108 0x0109 0x010A 0x010B 0x010C 0x010D 0x010E
0 0 0 17
*(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); }
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