Step 1: Work An Example Yourself: C Programming-Fundamentals 1-4 Coursera

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 44

C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

This figure shows a high-level overview of the programming process.

The above figure shows how you should approach designing your algorithm.

Step 1: Work an Example Yourself


which has a "yes or no" answer, we probably want to work at least one example that comes up
with a "yes" answer, and one that comes up with a "no" answer.

If you get stuck at this step, it typically means one of two things. The first case is that the problem
is ill-specified—it is not clear what you are supposed to do.

The second case where Step 1 is difficult is when you lack domain knowledge

Step 2: Write Down What You Just Did


Step 3: Generalize Your Steps
Sometimes you may find it difficult to see the pattern, Doing more instances of the problem will
provide more information for you to consider, possibly giving you insight into the patterns of your
algorithm.

This process is often referred to as writing 'pseudo-code'

Step 4: Test Your Algorithm


C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

Eg of Algorithm

Variable

 An identifier is the formal programming term for a word that can be used to name something

An assignment statement starts with an lvalue on the left. An lvalue (pronounced “el-value”)
must be something that “names a box”

 The rvalue (pronounced “are-value”) must be an expression whose value shall be placed in the
box.

Functions
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

A return statement starts with the keyword return, which is then followed by an expression. The
effect of this statement is to say what the "answer" is for the current function, leaving its
computation and returning to the code that called it.

we must first group together the variables belonging to one particular function into a larger box,
labeled with the function’s name, which is called a frame (or stack frame, since they are located
on the call stack).

Scope of a variable

To determine which variable a name refers to, we must first determine which variable(s) with that
name are in scope at the reference

If multiple variables are in scope, we select the one whose declaration is in the innermost
enclosing block. That is, if you went backwards out of blocks, through open curly braces, the
variable which would go out of scope first is the one to use.

If multiple variable in scope take innermost 1st


C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

;The f in printf stands for “formatted,” 

Another type of special information we can include in the string is escape sequences.

the first of which is a backslash (\)

\n newline \t tab
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

IF ELSE

C permits if with no else, which is equivalent to an empty “else” block

switch/case

When the execution arrow reaches the break keyword, it jumps to the close curly brace which
ends the switch statement.

. When the execution arrow passes from one case into the next like this, it is called “falling
through” into the next case.

Shorthand
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

Another possible shorthand is to omit the curly braces around single statement blocks of code in
certain cases. it is highly inadvisable to write code this way.

While Loops

do/while Loops

 By contrast, a do-while loop is guaranteed to execute its body at least once because it executes
the loop body before ever checking the condition.

For Loops

it does not introduce any new behavior, but instead provides a more convenient syntax for a
common programming idiom. 

There are two possible behaviors that a programmer might want when leaving the loop
body early.

Break One behavior would be to exit the loop completely

break;
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

Continue

Executing the continue statement jumps to the top of the innermost enclosing loop 

In the case of a for loop, the “increment statement” in the for loop is executed immediately before
the jump.

continue;

Hardware Representations

Binary Numbers

Hexadecimal
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

DATA TYPES

 In particular,
sizes depend on the hardware and the compiler—the program that turns your code into
instructions the computer can actually execute 

ASCII

Examples of chars and ints. At first glance, c and x appear identical since they both have the
binary value 65. However, they differ in both size (c has only 8 bits whereas x has 32) and
interpretation (c’s value is interpreted using ASCII encoding whereas x’s value is interpreted as
an integer). Similarly, y and z are identical in hardware but have differing interpretations because
y is unsigned and z is not.

 ints are actually represented using an encoding called two’s complement, in which half of the
2^{32} possible bit patterns are used to express negative numbers and the other half to express
positive one

Another pair of qualifiers you may run into are short and long which decrease or increase the
total number of bits dedicated a particular variable, respectively.s.

Float
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

One way we could (but often do not) choose to represent real numbers is fixed point. We could
take 32 bits, and interpret them as having the binary point in the middle. That is, the most
significant 16 bits would be the “integer” part, and the least 16 bits would be the “fractional” part. 

Precision

. A double takes up twice as much space as a float. This may not matter for a single variable, but
some programs declare thousands or even millions of variables at a time. If these variables do
not require the precision of a double, choosing a float can make your code run faster and use
less memory with no loss of correctness.

Print

The types of constants can be modified by applying a letter suffix if needed (U for unsigned, L for
long, and f for float): 3.14f is a constant with type float, and 999999999999L is a constant with
type long int.

When the two operands have different types, the compiler attempts to add a type
conversion (sometimes called a type promotion) to make the types the same.

 The third common way that the bit representation can be changed during an automatic
conversion happens when a longer integer type is converted to a shorter integer type. Here, the
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

bit pattern is truncated to fit—the most significant bits are thrown away, and only the least
significant bits are retained.

We will note that while understanding when to cast is important, understanding that you should
generally not cast is even more important—sprinkling casts into your code to make errors go
away indicates that you are not actually fixing your code, but rather hiding the problems with it.

Explicitly requested conversion is called casting and is written in the code by placing the desired
type in parentheses before the expression whose value should be converted. For
example, (double)x evaluates x (by reading the value in its box), then converts it to a double.

casting has very high operator precedence

A string is a sequence of characters that ends with a special character called the null terminator,
which can be written with the character literal '\0' (pronounced “backslash zero”) that signals the
end of the string.

Image

While there are many ways to represent a color as a number, the most common is RGB
Typically, this encoding is done with each component being represented on a scale from 0 to
255. The RGB values for the color red are: R=255, G=0, B=0.

You may have noticed that computers typically have a variety of image formats, such as JPG,
BMP, PNG, TIFF, and many others. Each of these encodes the image numerically, 
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

Struct declarations do not go inside functions; they live in the global scope of the program, next
to function declarations and definitions.

Ending the tag in “_t” is a convention that makes it easier to recognize the name as identifying a
type throughout your code. 

TYPE DEF

Padding ===========

struct node{

int I;

double j;

char array[12];

Size of struct is largest data type ie double

int I = 1 double =8
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

double j = 1 double=8

char array[12] = 2 double = 16bytes

Therefore total size is 32 bytes

NOTE(Padding concept):
If 2 data type are same they can occupy the same allocated block

UNIONS
union var_name{

int I;

char[20];

};

It takes the memory it takes to store the largest element in this case 20bytes for char[20] and al
elements share that

If char[20] is full and you try to store int I it will cause seg fault

Enumerated Types
enum threat_level_t {

LOW,

GUARDED,

ELEVATED,

HIGH,

SEVERE

};

 Each level is assigned a constant value, starting with 0. 

The enumerated names are constant—they are not assignable variables.

The convention for indicating that a name denotes a constant is to write the name in all
uppercase. However, variables of the enumerated type can be created, and assigned to
normally.

eg

void printThreat(enum threat_level_t threat){


C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

switch(threat) {

case LOW:

printf("Green/Low.\n");

break;

case GUARDED:

printf("Blue/Guarded.\n");

break;

case ELEVATED:

printf("Yellow/Elevated.\n");

break;

case HIGH:

printf("Orange/High.\n");

break;

case SEVERE:

printf("Red/Severe.\n");

break;

STEP 3

Generalizing Values
Generalizing Repetitions
Generalizing Conditional Behavior

Step 5: Translation to Code

Function declaration
1. we may need to do in writing down the function declaration is to figure out its
parameter types and return type.
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

2. replace the generalized algorithm from Step 3, written as comments ten write code at ls
of comment

 In C, there are two forms of comments: // comments to the end of the line, and /*...*/ makes
everything between the slash-star and the star-slash into a comment.

Repetition
If your algorithm calls for you to "stop repeating things" or "stop counting" you will want to
translate that idea into a break statement. Meanwhile, if your algorithm calls for you to skip the
rest of the steps in the current repetition, and go back the start of the loop, that translates into
a continue statement.

Decision Making

Whenever your algorithm calls for you to make a decision, that will translate into
either if/else or switch/case.

Math

Names

Altering Values
manipulates the values that it works with, these translate into assignment statements

The answer is...

return statement

Complicated Steps
something that you cannot translate directly into a few lines of code—you should call another
function 

do not worry about defining the function yet. Instead, just call the function you will write in the
future 

Top-down design
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

The process of taking large, complex pieces, and separating them out into their own function

Whenever you have a chance to pull a well-defined logical piece of your program out into its own
function, you should consider this an opportunity, not a burden.

Compilation Process

These header files—and header files in general—primarily contain three things: function


prototypes, macro definitions, and type declarations.

Macro eg #define EXIT_SUCCESS 0

For one, if the programmer ever needs to change the constant, only the macro definition must be
changed, rather than all of the places where the constant is used.

The standard header file limits.h contains constants specifically for portability. These constants
describe the maximum and minimum value of various types on the current platform.

 it can use INT_MAX and INT_MIN respectively

Macros

#define SQUARE(x) x * x

 SQUARE(3) to 3 * 3, or SQUARE(45.9) to 45.9 * 45.9

 text z-y, resulting in z-y * z-y. Note that this will compute z- (y*z) -y,

stdint.h defines types such as int32_t (which is guaranteed to be a 32-bit signed int on any
platform), or uint64_t (which is always a 64-bit unsigned int).

const char * as being the type for a literal string

NOTE

Compiler errors can be a source of confusion and frustration for novice programmers. One key
rule in dealing with them is to try to fix them in order,
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

 If parts of an error message are completely unfamiliar, try to ignore them and see if the rest of
the error message(s) make sense

Compilng

1. The output of the preprocessor is stored in a temporary file


2. The compiler reads the pre-processed source code and translates it into assembly
3. The next step is to take the assembly that the compiler generated and assemble it into
an object file.
4. Linking the program takes one or more object files and combines them together with
various libraries, as well as some startup code, and produces the actual executable
binary

Once the compiler has parsed your program, it type-checks the program. Type-checking the
program involves determining the type of every expression

Once the compiler finishes checking your code for errors, it will translate it into assembly

You can ask the compiler to optimize your code—transform it to make the resulting assembly run
faster—by specifying the -O option

Programs are usually compiled with no optimizations for testing and debugging and then re-
compiled with optimizations once they are ready for release/use.

You can request that gcc stop after it assembles an object file by specifying the -c option. For
example, gcc -c xyz.c will compile xyz.c into xyz.o.

different name for the object file gcc -c xyz.c -o awesomeName.o 

Linker errors—indicated by the fact that they are reported by ld (the linker’s name)

MAKE and what it does

When make is run, it starts from a particular target—something that it can build out of other
things. A common starting target might be your entire program. make first checks if the target is
up-to-date. Checking that a target is up-to-date requires checking that all of the files that the
target depends on are themselves up-to-date, and that none of them are newer than the target.
For example, the target for the whole program may depended on many object files. If any such
file is not itself up-to-date (for example, the object file may depend on a .c file, which just got
changed), it is rebuilt first. make then follows whatever rule was specified for the target to build it
from its dependencies. If the target is already up to date, then it does nothing.

eg: of makefile

(targetfile)myProgram: (These are dependancies) oneFile.o anotherFile.o

gcc -o myProgram oneFile.o anotherFile.o

oneFile.o: oneFile.c oneHeader.h someHeader.h


C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

gcc -std=gnu99 -pedantic -Wall -c oneFile.c

anotherFile.o: anotherFile.c anotherHeader.h someHeader.h

gcc -std=gnu99 -pedantic -Wall -c anotherFile.c

Using a variable to store compiler flags

CFLAGS=-std=gnu99 -pedantic -Wall

myProgram: oneFile.o anotherFile.o

gcc -o myProgram oneFile.o anotherFile.o

oneFile.o: oneFile.c oneHeader.h someHeader.h

gcc $(CFLAGS) -c oneFile.c

anotherFile.o: anotherFile.c anotherHeader.h someHeader.h

gcc $(CFLAGS) -c anotherFile.c

CLEAN

 The clean target is a bit different in that it does not actually create a file called clean (it is
therefore called a “phony” target). Instead, it is a target intended to remove the compiled
program, all object files, all editor backups (*.c~ *.h~), 

.PHONY: clean

clean:

rm -f myProgram *.o *.c~ *.h~

# A good start, but we lost the dependencies on the header files

CFLAGS=-std=gnu99 -pedantic -Wall

myProgram: oneFile.o anotherFile.o

gcc -o myProgram oneFile.o anotherFile.o

%.o: %.c

gcc $(CFLAGS) -c $<


C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

.PHONY: clean

clean:

rm -f myProgram *.o *.c~ *.h~

In make, we can write generic rules. A generic rule lets us specify that we want to be able to
build (something).o from (something).c, where we represent the something with a percent-sign
(%)

n this rule, we cannot write the literal name of the source file, as it changes for each instance of
the rule. Instead, we have to use the special built-in variable $<, which make will set to the name
of the first prerequisite of the rule 

 We could make every object file depend on every header file (by writing %.o : %.c *.h)

CC = gcc

CFLAGS = -std=gnu99 -pedantic -Wall -O3

DBGFLAGS = -std=gnu99 -pedantic -Wall -ggdb3 -DDEBUG

SRCS=$(wildcard *.c)

OBJS=$(patsubst %.c,%.o,$(SRCS))

DBGOBJS=$(patsubst %.c,%.dbg.o,$(SRCS))

.PHONY: clean depend all

all: myProgram myProgram-debug

myProgram: $(OBJS)

gcc -o $@ -O3 $(OBJS)

myProgram-debug: $(DBGOBJS)

gcc -o $@ -ggdb3 $(DBGOBJS)

%.dbg.o: %.c

gcc $(DBGFLAGS) -c -o $@ $<

clean:

rm -f myProgram myProgram-debug *.o *.c~ *.h~

depend:

makedepend $(SRCS)

makedepend -a -o .dbg.o $(SRCS)

# DO NOT DELETE

anotherFile.o: anotherHeader.h someHeader.h


C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

oneFile.o: oneHeader.h someHeader.h

Parallelizing computation
 the -j option (, make -j8 runs up to 8 tasks in parallel)

Black box testing- making test case without knowing src code

Unlike black box testing, white box testing involves examining the code to devise test cases.

Practical Tips for Designing Test Cases


 if you want to test two different error conditions, you need two different test cases: one for
each error condition. 
 Test exactly at the boundary of validity. maybe the programmer wrote < when he should
have written <= or >=

 For numerical inputs, these would generally be negative, zero, and positive. One is also
usually a good number to be sure you cover
 For sequences of data, your tests should cover an empty sequence, a single element
sequence, and a sequence with many elements.
 For characters: lowercase letters, uppercase letters, digits, punctuation, spaces, non-
printable characters
three levels of test coverage: statement coverage, decision coverage, and path coverage

Statement coverage means that every statement in the function is executed.

decision coverage— this means we construct a test case where the expression evaluates to true,
and another where it evaluates to false. CFG for one function at a time
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

achieve path coverage, our test cases must span all possible valid paths through the control flow
graph

 algorithm by hand=statement coverage 

This approach requires development of code which is not part of the main application—a
program which not only sends the requests into the network model, but also tracks the status of
those requests and checks for the proper outcomes. This additional program is called a test
harness—

An invariant is a property that is (or should be) always true at a given point in the program.

 assert(expr); checks that expr is true

-DNDEBUG option  turns off asserts

Scientific method of debugging

Ask A Question

we should aim for more focused questions: “On which line of code does my program crash?” or
“Why does my program call myFunction with x=3 and y=-42?”.

A breakpoint is set on a particular line of code, and instructs the debugger to stop the execution
of your program whenever the execution arrow is on it.

Watchpoints specify that you want to stop the program when a particular “box” changes.

Correct hypothesis

 “My program is broken”

 “My program is dividing by 0 on line 47 if y is odd and z is a perfect square.”

The first characteristic of a good hypothesis that this exhibits is that it is testable.

The contrived hypothesis we presented at the end of the previous paragraph is quite testable: we
specify a certain category of inputs (y is odd and z is a perfect square) and exactly what behavior
we expect to observe (division by 0 on line 47).
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

Constructing test cases


construct a test case with the values you were thinking of, and see if your program exhibits that
behavior. Also, construct other test cases that do not meet the conditions to see if you were too
specific.

Inspecting the internal state of the program

Adding asserts

Code inspection

Another method to test your hypothesis is to inspect and analyze your code. Sometimes a simple
hypothesis can be tested with a quick inspection.

Debugging gdb tool


 if you compile your program in multiple steps (object files, then linking), you should include
-ggdb3 at all steps.

start: Begin (or restart) the program’s execution. Stop the program (to accept more commands)
as soon as execution enters main.

run: This command runs the program (possibly restarting it). It will not stop unless it encounters
some other condition that causes it to stop (we will learn about these later).

step: Advance the program one “step”, in much the same way that we would advance the
execution arrow when Advance the program one line of code. However, unlike step, if the current
line of code is a function call, gdb will execute the entire called function without stopping. This
command can be abbreviated n.

print: The print command takes an expression as an argument, evaluates that expression, and
prints the results. Note that if the expression has side-effects, they will happen, and will affect the
state of the program (e.g., if you do print x = 3, it will set x to 3, then print 3). You can
put /x after print to get the result printed in hexadecimal format. This command can be
abbreviated p (or p/x to print in hex). for example, if a is an array, you can do p a[0]@5 to print
the first 5 elements of a.

executing code by hand

display: The display command takes an expression as an argument, and displays its value


C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

every time gdb stops and displays a prompt You can set a breakpoint with the break command,
followed by either a line number, or a function name

(gdb) break 7 if i==250000 conditional breakpt

cond 1 i==250000

Two other useful commands to control the execution of the program are until, which causes a
loop to execute until it finishes (gdb stops at the first line after the loop), and finish (which can be
abbreviated fin), 

Signals
Whenever your program receives a signal, gdb will stop the program and give you control.

The first is SIGSEGV, which indicates a segmentation fault. 

SIGABRT, which happens when you program calls abort() or fails an assert. 

SIGINT, which happens when the program is interrupted—e.g., by the user pressing Control-c

Pointer
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

lines like these are illegal: int *ptr = &3; and int *ptr = &(x + y) since they do not point to any box .
ptrs can only hold addresses

Code
a program itself can be represented by a series of numbers. Producing these numbers is the job
of a compiler

The compiler converts the C code into object code and also assigns each encoded instruction a
location in memory. 
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

Static Data
 Unlike a variable that is declared inside a function and is no longer accessible when the function
returns, static variables are accessible until the entire program terminates (hence, the
term static ).

The Heap (in purple) stores dynamically allocated data. The Stack (in orange) stores the local
variables declared by each function.

Arguments of a function lie in the stac frame of the function that called it

Last box in stack frame is return address

programs use a pointer with the numeric value of 0—which has the special name, NULL to mean
“does not point at anything. ….. there is no answer

When we use NULL, we will represent it as an arrow with a flat head

The NULL pointer has a special type that we have not seen yet—void *

Because we do not know what a void * actually points at, we can neither dereference it 

pointer to struct

q->x (which means exactly the same thing as (*q).x)

Pointers to Pointers
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

 (e.g., p has type int *, so &p has type int **). Whenever we take the address of something, we


“add a star” to the type. \ Note that * and & are inverse operations—if we write *&e or &*e, they
both just result in e

const
, it is good time to introduce the notion of const data—data which we tell the compiler we are not
allowed to change. 

const int x = 3; // assigning to x is illegal

const int * p = &x;\\ cannot assign value to the box arrow points to

int const * p = &x; is same

int * const p = &x;\\can change box but not arrow

const int * const p = &x; cannot change both

Aliasing

casting (int)f makes p=3

casting (int*)&f considers f to be already int converts 3.14 to binary then hex than int
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

Ptr=Ptr+1 point to the nxt data type(eg int)

so if ptr is of int* then compiler will increment that many number of bytes eg 4

this does not point to a known address and is generally not used

ArraYS

We can initialize an array

int myarr[3]={1,2,3}

or we can initialize a struct

rect p={.x=3,.y=5}

we can initialize multiple structs

rect arr[2]={ {.x=3, .y=5},{.x=3, .y=3}}

arr is a ptr to start of array

int *y=arr means

y is a ptr to same address as arr

*y is 1st element of array

ptrs arithmetic result+=ptr ptr++

indexing ptr[i]

int arr[] can be used to define argument as array in fn

.DANGLING POINTERS
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

cannot return and array from function

after function memory is deallocated and stack frame destroyed it points to something that is not
there

subfunction can return ptrs of arrays defined in main fn

SIZEOF AND SIZE_T

sizeof operator defines the number of bytes of a function

size_t is used to declare a variable that holds size_t

eg:

size_t x=sizeof(int)+sizeof(*p)

STRINGS

 the null terminator character, '\0'

When you declare something as const it stores in static section of stack


C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

Accessing read only data gives a segmentation fault

When we want to modify a string, we need the string to reside in writeable memory, such as the
frame of a function or memory that is dynamically allocated by malloc (which you will learn about
in Course 4). To make space for a string in a function’s frame, we need to declare an array of
chars with sufficient space to hold all of its characters, plus its null terminator.

Use valgrind to detect if strings not ending with \0

The C library strcmp function behaves slightly differently than the one we are about to write in the
video—it returns 0 if the strings are equal, and non-zero if they are different. In fact, it returns a
positive number if the first string is “greater than” the second string and a negative number if the
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

first string is “less than” the second string. Here “greater than” and “less than” refer
to lexicographic order 

The comparison is case sensitive (so abc is different from Abc), but there is another
function, strcasecmp which performs case-insensitive comparison.

strncpy =takes parameter n which is string size if dest<=n dest not null terminated meaning no
space for null terminatorw

strcpy – just dumps without checking mem at destination dangerous donotuse

strdup-dynamically allocates memory then cpy string

String to int

atoi –convert to dec

strtol-lets you specify base as well as , end ptr to whatever is there after numerical value

Multidimesional arrays

CAN ALWAYS LEAVE ROWS UNSPECIFIED

data type is …………….. int myMatrix [][]

double myMatrix[4out][3in];

indexing eg matrix [1][0]

in myArray[2][1]

myArray[2][1] is an lvalue as it points to a box whereas myArray[2] ptr is not stored anywhere
and jus cal from myarray ptr therefor it is not an lvalue
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

When we initialize an array in this fashion we can leave off the first dimension, as the compiler
can determine how many elements there are from the initialize

eg to initialize

double myMatrix[][3] = { {1.0, 2.5, 3.2}, //elements of myMatrix[0]

{7.9, 1.2, 9.9}, //elements of myMatrix[1]

{8.8, 3.4, 0.0}, //elements of myMatrix[2]

{4.5, 9.2, 1.6} }; //elements of myMatrix[3]

in char [1][3][4]

if we say char[1] it’s the address to a 2d array

if we say char[1][0] it’s a 1d array

if we say char[1][2][4] its an element

An array of pointers

data type …………….. int ** arr

double row0[3]={11,22,56};

double row1[3];

double row2[3];

double row3[3];

double * myMatrix[4] = {row0, row1, row2, row3};

access 2nd element of 1st array

*(array[0]+1)
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

Both types are not compatible with one another

ARRAY OF STRINGS

Above fig may waste space if words smaller than max length

it is common to end an array of strings with a NULL pointer, such as this

const char * words2[] = {"A", "cat", "likes", "sleeping.", NULL};

abstraction ……………. const char ** ptr = words2;


C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

NOTE

str are displayed as a ptr value itself ie

 if an array of word2[] is initialized as a double pointer *word2 would be the


string and word 2 would be the address to be incremented
 if an array of word 2[] was initialized as a double pointer for int **word2 would
be int and (*word)++ incremented

FUNCTION POINTER

Declaration

 (return type) (*ptr)(arg type)

eg int (*elf)(int)

a arbitrary fn…… int elf (int a){}

int (*elf)(int) =&elf

(*elf)(10);

 fnction ptr as array

int(*ptr[])(int, int)={fn1,fn2,fn3}

(*ptr[2])(1,3)

executes fn3

 void fn (int a)
void fn1(void (*fn)(int))
fn1(fn)

Quicksort fn

strings

void sortStringArray(const char ** array, size_t nelements) {

qsort(array, nelements, sizeof(const char *), compareStrings);


}

int

void sortIntArray(int * array, size_t nelements) {


C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

qsort(array, nelements, sizeof(int), compareInts);

must define separate compare function


for must change from void * to const char*const* or const int* using cmp
const char * const * s1ptr = s1vp;
const int * n1ptr = n1vp;

Never use gets() leads to buffer overflows

format string attacks

inp

prinftf(inp) user can disp any string

in sql can add commands to delete databases

We can use 2 methods to solve repetitive problems iterations and recursions

each can be expressed as the other

Recursion is based on function calls

int factorial(int n){

if(n<=0){

return 1;

return n*factorial(n-1)

1, Recursive function must always have a base case in this case the if stmt

recursive functions always move towards the base case

But regular recursion is slow it computes same thing many time ,,, we can use
memorization to solve this

a function call is a tail call if it returns immediately after

TAIL RECURSION

eg same fact as tail call

int f(a,ans){
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

if (a<=0){

return ans;

return f(a-1,ans*a)

int fact (int b){

f(b,1);}

thus 2 functions a main and a helper

genral syntax for helper

f(a,a1,,,,,,an, ans)

base condition

return ans

return (exp1,exp2.,,,,expn,ans)

MUTUAL RECURSION

2 recursive functions that call each other

prototype of 2nd fn must be mentioned before 1st

eg. to calc if a no. is even or odd

prototype

int fen(unsigned int a){

if a==0 return 0

if a==1 return 1

return fod(unsigned int a-1){

int fod(unsigned int a)

if a==1 return 0

if a==0 return 1

return fen(n-1)

Proof of base case

0 or 1
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

asumming k=true prove k+1 is true

OS Concepts

since errno is global (there is one for the entire program), you must take care not to call anything
that might change it before you test it or call perror.

//BROKEN CODE

int x = someSystemCall();

if (x != 0) {

printf("someSystemCall() failed!\n"); //may change errno

perror("The error was: ");

COMMAND LINE ARGUMENTS

int main(int argc, char ** argv) {

//...whatever code you want goes here...

 int argc is the count of how many command line arguments were passed in (it stands
for argument count)

second is an array of strings, which contains the arguments that were passed in (it stands
for argument vector).
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

getopt() for taking arguments from cli

ENVIRONMENT POINTER

main can potentially take a third argument: char ** envp

access the environment variables with the functions getenv, setenv, putenv, and unsetenv

PROCESS CREATION

To create another process in a running program we make use of fork() it creates a process
identical to the parent process called child process

execve() sys call replaces the child process with a script or program it specifies the argv and
envp to pass to it

it stores the argv and envp and moves the arrow to start of script or binary

then it calls main() if main declared with less arg than child process it ignores it

main() returns to the function that calld it then procedes exit() system call to terminate the child

process

OPENING A FILE

Reading a File
Once we have our file open, we might want to read input from it. We typically will use one of
three functions to do so: fgetc, fgets, or fread.

int fgetc(FILE * stream); --------------------------------can be used in func as FILE *f


C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

while(c=fgetc(f)!=EOF)

char * fgets(char * str, int size, FILE * stream);

while(fgets(arr1,size,f)!=NULL)

if(strchr(arr1,’\n’)!=NULL)-------checks if entire line can be accommodated

size_t fread (void * ptr, size_t size, size_t nitems, FILE * stream);

ptr=dest

size=byte of data type

nitems =number of items of that data type

stream=file

WRITING TO A FILE

int fputs(const char *str, FILE *stream)

int fprintf(FILE *stream, const char *format, ...)

int fputc(int char, FILE *stream)

size_t fwrite(const void * ptr, size_t size, size_t nitems, FILE * stream);

CLOSE

fclose(f)

DYNAMIC MEMORY ALLOCATION

Instead of stack memory is stored on the heap and freed after it serves its purpose
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

malloc

malloc points to null if memory unallocated

eg array declaration int* p=malloc(7*sizeof(*p))

Shallow vs. Deep Copying


polygon_t * p2 = p1; //just copy pointer

p[0]=1 p[1]=2 etc

polygon_t * p2 = malloc(sizeof(*p2));
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

*p2 = *p;

polygon_t * p2 = malloc(sizeof(*p2));

p2->num_points = p1->num_points;

p2->points = malloc(p2->num_points * sizeof(*p2->points));

for (size_t i = 0; i < p2->num_points; i++) {

p2->points[i] = p1->points[i];

free

note:all frames in heap must be freed

eg for(size_t i=0;i<4;i++){

free(p[i]);
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

free(p)

cannot free a middle of a allocation like p++ free(p) pointer must always point to zeroth element

realloc

If no area in the heap of the requested size is available, realloc returns NULL.

p=realloc(p, 5*sizeof(int))

getline

int main(void){

size_t sz=0;

ssize_t len=0;

char* line=NULL;

FILE *f=fopen(“direc”,”r”);

while(len=getline(&line,&sz,f) >=0)

free(line);

TO COPY IT TO OTHE ARRAY

char **store =NULL;

while(len=getline(&line,&sz,f) >=0)
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

lines = realloc(store, (i+1)*sizeof(*store);

store[i] = line;

line=NULL;

i++;

VALGRIND

--track-origins=yes

--vgdb=full --vgdb-error=0

path/to/gdb ./tst

inside gdb

monitor who_points_at 

ABSTRACTION

Seperation of

Implementation(how it does it) and interface(what it does)

eg. for fprintf interface is writing data to file

how it writes it is interface

Hierarchial abstraction

Design in such a way that smaller function together make up a single function ie topdown design
methodology bottom up

can write stubs if a function is not written ie expected output

Readability

Function should fit in a single screen

Naming conventions

_t for types eg node_t

ALLCAPS for constants

Comment about the interface at the start of each function


C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

Git

-commit regularly

-bisect to find last broken

-pull push

-multiple version of the present (branches)

NOTES(STRUCTS)
 Flexible arrays at end of struct
 1 struct can only have a single flexible array
 items preceding it must be defined
 struct declarations must always be at the top before any function prototype
 when passing struct pointers pass using struc**
 when resolvinf addressing use struc*

ARRAY OF STRINGS

char **name=name=malloc’d with (no*(char *)

char *name=*(name+i)=malloc’d with (no*(char)

eg char **orderedIds;

orderedIds = malloc(4 * sizeof(char*));

for (int i = 0; i < 5; i++){

orderedIds[i] = malloc((5) * sizeof(char));

if(orderedIds[i]==NULL){

perror("");

exit(EXIT_FAILURE);

orderedIds[i]="enterme";

printf("\n{");

for (size_t i = 0; i < 5; i++){

printf("%s, ",orderedIds[i]);

ARRAY OF INTS(DOUBLE PTRS)

int **dt=dt=malloc’s with int*


C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

int *dt=*(dt+i)=molloc’s with int*

int dt=**(dt+i)=6

eg

orderedIds = malloc(4 * sizeof(int *));

for (int i = 0; i < 5; i++){

*(orderedIds+i) = malloc(sizeof(int *));

if(*(orderedIds+i)==NULL){

perror("");

exit(EXIT_FAILURE);

**(orderedIds+i)=12;

printf("\n{");

for (int i = 0; i < 5; i++){

printf("%d, ",**(orderedIds+i));

Make a stuct with only array of strings and try to input

then make a next ptr

then put in for loop

FUNCTION POINTER

int fun1(char * r,int a){

FP

returntype (*var)(argument)= fun address;

eg
C PROGRAMMING-FUNDAMENTALS 1-4 COURSERA

int (*fun_y)(char*, int)=fun1;

fun_y(“this”,2);

ARRAY of FP

int (*fun_y[])(char*, r)={fun1, fun2, fun3}

fn(fun_y)

You might also like