C Programming Flashcards
Pointers
For pointers “&” is the address operator
“*” is the dereference operator
Pointers provide a elegant of indirection to accessing program state,
A pointer is a variable that contains the address of a variable.
A pointer can only point to a object type(basic or dervied) suh as int, char, strcut, another pointer etc.
When delcaring a pointer it doesn’t point to anything unless initialized. Only memory is allocated
Dynamic memory allocation
allows a program to adjust to changes in sizes and space needs as it runs, allocating more space as it needs it and freeing up space it no longer needs
Program Scope
A variable’s scope defines when its name has meaning. In other words, scope defines the set of program code blocks in which a variable is bound to (associated with) a program memory location and can be used by program code.
Global Variables
variables that are declared outside the function body.
Global variables remain permanently in scope and can be used in any code in the program because they’re always bound to one specific memory location.
In C, global variables are saved in data segment
Advice: Global variables ….
avoid programming with global variables whenever possible.
Local variables
local variables are only in the scope inside the function in which they are defined.
Space to store a parameters value is allocated on the stack when the function gets called, and gets deallocated from the stack when the function returns.
Each activation of the function its own bindings for its parameters and local variables
For recursive calls, each call gets. a separate stack frame containing a space for its parameters and local variables.
Program address
a program’s address space represents storage locations for everything it needs for execution: storage for instruction and data.
Program’s address space can be thought of as an array of addressable bytes, each use of address in the program’s address space stores all or part of a program instruction or data value
Never dereference a NULL pointer
(*) is the dereference operator
“&” : is an address operator
“*” : is a dereference operator
example:
int *x;
int y =5;
x =&y;
printf(“%d”, *x);
A pointer can only point to one type (basic or derived)
Ex: int, char, a struct, another pointer, etc.
After declaring a point: int *ptr, ptr doesn’t actually point to anything yet. We an either make it point to something that already exists, or
allocate room in memory for something new.
array declaration
int ar[5]; // decare a 5 elemtn array
int arr[] = {78, 76}; //declares and fills a 2-elemtn array
int arr[5];// declares 5 eleent integer array
In C arrays are collections ocontinguous memory locations holding identical types
in java , arrays are collection of like items
accessing Arrays
arr[i]; returns the i-th element
index starts at 0
sizeof(ptr) gives the memory
len(arr) tells your size of array
how to acess poitners and dereference
let arr be an array
arr is like a pointer to first element of array
arr[0] is the same as arr[0]
arr[2] is the same as *(arr+2)
use pointers to pass arrays to functions
use pointer arithmetic to access arrays more conveniently
compiler is smart enough to identify type
ptr is just a memory address, we can add to the meory address to traverse an array
ptr + 1 will return pointer to next element
arr[20][40][60][ ][ ]
int * ptr;
ptr points to arr[0]
*ptr gives 20
ptr = ptr +1 ; this will give ptr ==104 which is the address of the next index not the value
what will (*ptr+1) do? what will *ptr++ do? what will *(ptr+1) do?
addr: 100. 104. 108 112 116
arr. [20]. [40]. [60]. [ ]. [ ]
what will (*ptr+1) do? 21
derference first then +1 to the value. 20+1
what will *ptr++ do? 20
post increment will give back a pointer, then defreerence first then adds 1 to the next address. So its will only increase theaddress after derefernce since a post increment.
what will *(ptr+1) do? 60
since ptr was changed to address 104 from last line, now its moves another 1 to 108 and then dereferences to 60.
*(ptr) ++ would give 20 without changing but 20 prints out but in a sense becomes 21 but without being printed.
int *p, arr[5]; declaration
p=arr+5;
arr=p+1;
Will any of the above create errors?
addr: 100. 104. 108 112 116
arr. [20] [ ] [ ] [ ] [ ]
p=arr+5;
will return garbage value, but no error.
will access the memory after 116 , which is garbage.
arr=p+1;
compiler error. type mismatch since arr is int array but p+1 is a int pointer
This will lead to errors . Illegal Lvalue
int * p, arr[5]; //delcaration
p=arr+5
*p=0;
what will happen?
Possible result in seg fault because the memory location being accessed may not be a valid address
int main (int argc, char **argv)
% ./a.out how are you?
what is *argv[3]?
*argv[3] is *(argv[3]) is ((argv+3))
all the above gives back a CHAR, single character
argv is [./aout ] [ out\0] [how\0] [are\0 ] [you?\0 ]
argv[3] gives back the first character of the 3rd string.
*argv[3] = ‘y’
Operator Legal
++, – , [], ==, != yes
Ptr + integer yes
Ptr - integer yes
integer - ptr NO (would be need to
negate pointer)
Pointers are always positive
Ptr – ptr Yes – returns an int
(distance in elements between pointers)
Ptr + ptr NO – not guaranteed to be an address
so K&R decided against
Ptr multiply ptr No - (just repeated addition).
…
*ptr=NULL;
pointers can be assigned NULL. Should not dereference bull pointers
do not dereference nnull pointer
int x = 10;
int * ptr;
ptr = &x;
*ptr=8;
what *ptr=8; does is changes the value of the address it is pointing at to 8. Dereferencing a pointer accesses the value that the pointer refers to.
ptr = &x;
this line initalizes tr to the address of x (ptr points to variable x)
int *ptr1, *ptr2, x, y;
x =8;
ptr2= &x; assigns ptr2 to address of x
ptr1=NULL;
*ptr2 = 10; memory location ptr2 points to its assigned 10
(changes the location ptr2 points to to the value 10.
y = *ptr2 +3; // y is assigne what ptr2 points to plus 3
ptr1 = ptr2; // ptr1 gets the address value stored in ptr2 (essentially both pointers are pointing to the variable x
*ptr1 = 100; // ptr1 changes data of the address its pointing to to 100. Now ptr2 is pointing to 100.
ptr1=&y;
*ptr1= 80;
now ptr1 has changed the value at y to 80.
y is whatever ptr2 points to and +3.
ptr2 i pointing to the address with a value of 10.
y= 10 + 3 = 13
ptr=20; // this assigns ptr to point to address 20 which is wrong.
ptr =&x;
*ptr=20; //this assigns 20 to the memory pointed to by ptr
ptr=NULL;
*ptr=6;
What will happen?
This will cause a crash as we are trying to modify something without assigning ptr to anything (seg fault)
.
Pointer Arithmetic
what does “ ptr + 1 “ return/give/do?
what does “ ptr++ “ return/give/do?
ptr+1 will return a pointer to the next element
ptr++ will move pointer to next index but after since its a post fix.
Pointers will not point to a value. Pointers hold a number that is a memory address. ITs just a value representing memory location. It “points” to your “residennce”
int * ptr = & x
This code will declare a variable ptr as a integer pointer and initilaized it to the address of where the variable x has been placed.
The following two statements are TRUE OR FALSE:
int*ptr = arr;
int * ptr = &arr[0]
True, the two lines are the same
The following two statements are TRUE OR FALSE:
int*ptr = arr[2];
int * ptr = *(arr+2)
True, the two lines are the same
what the the following statement return?
int val=2;
int* ptr = &val;
printf(“%p”, ptr);
It prints the address of where val is stored
All arrays are just pointers whose value (the address the point to) cannot change
arr[ ] is an array
The following are equivalent:
arr[0] is same as *arr
arr[2] is same as *(arr+2)
An array in C does not know its own length (bounds are not checked. This leads to possiblity of accessing memory outside of array.
If we ever use a method that will use and traverse out array we should pass not only the array but also its size.
Errors with pointers:
SegFaults: accessing memory that isn’t allocated to you
Are very hard to find.
Buffer Overflow can lead to security problems.
Which would lead to problems at compile time?
int*p, arr[5];
1) . p = arr +5;
2) arr = p + 1;
arr= p + 1 will lead to compile time error
p = arr + 5 wont lead to compile time error but runtime error of segfault
What will the following do or give for the array?
int val = 120;
int * ptr = &val;
int a = 12;
int ** pptr = &ptr;
val = a;
int arr[] = { 11, 2, 35, 469 };
*(arr + 2) = **pptr;
{11, 2, 12, 469}
35 is changed to 12
What will the following return or give for variables x, y, z?
int arr[] = { 7, -11, 30, 104 }; int * p = arr; int x = *p++; int y = *(p++); int z = *p - 3;
x=7
y = -11
z= 27
Notice post increment occurs after the line of code is completed
Pointer Arithmetic
A pointer is just referencing a memory address. We can add to the memory adress to traverse the array (of memory)
ptr + 1 : will return a pointer to the next element
x++ is a postfix operator where x is evaluated and the incremented after
++x is a prefix operator where x is incremented then evaluated after incrementing.
Operations that are valid:
++ , – , [ ] , == , !=
ptr + int
ptr - int
ptr - ptr
The following are not allowed:
int - ptr
ptr + ptr
ptr (multiply) ptr
int x; int* ptr; ptr = &x; *ptr = 73; int** ptrToPtr = &ptr; **ptrToPtr = 17; int y = 7; *ptrToPtr = &y; ptr = &x; printf(“Value of **ptrToPtr: %d\n”, **ptrToPtr);
what is printed
17
Functions()
modularity
Reuse
Debug
Declaration + implementation = complete defintion
Functions overview
//Declaration void foo ( int x, int y);
function declaration with parameter types.
Example: Swap
void foo (int x, int y) { int temp; temp = x; x =y; y = temp;
Function does not do anything actually , while values are switched they only occur in the function space/execution and gets wiped at function completion
Variables are allocated
when program is run
In C, variables are passed by value, not the variables. Only the value they hold are passed into the function
to update a variable resort to pointers
void swap (int *x, int *y){
..
how to properly set up code?
void incrementPtr(int **ptr){
..
Accessing Array element:
arr[i]; // this returns the ith element
arr will always point to the first element in the array. So *arr and arr[0] are the same
arr[2] is te same as *(arr+2)
Arrays in C are different than in Java
We use pointers to pass arrays to functions’
Use pointer arithmetic to access arrays more conveniently
Pointers are just memory addresses
Adding to a pointer can mean traversing an array or to add to the value dereferenced
ptr + 1 will return a pointer to the next element in the array ( compiler will know the size/type of ptr and increment the appropriate size)
ptr++ means to evaluate ptr (dereference ptr, *ptr) first, then increment it.
–ptr means to decrement ptrs first, then evaluate it (dereference it).
The sequence of code below will produce the following with the array ptr is pointing to :
20, 40 , 60 , NULL, NULL
printf(“%d, “,ptr+1); //will derefence then add: 20 + 1 =21
printf(“%d, “,ptr++); // will dereference then move pointer after: 20 ( then pointer moves to next index)
printf(“%d\n”, *(ptr+1)); // pointer moves to next index then dereferences : goes from 40 to 60, then references the number to 60.
Pointers are just memory addresses
Adding to a pointer can mean traversing an array or to add to the value dereferenced
ptr + 1 will return a pointer to the next element in the array ( compiler will know the size/type of ptr and increment the appropriate size)
ptr++ means to evaluate ptr (dereference ptr, *ptr) first, then increment it.
–ptr means to decrement ptrs first, then evaluate it (dereference it).
The sequence of code below will produce the following with the array ptr is pointing to :
20, 40 , 60 , NULL, NULL
printf(“%d, “,ptr+1); //will derefence then add: 20 + 1 =21
printf(“%d, “,ptr++); // will dereference then move pointer after: 20 ( then pointer moves to next index)
printf(“%d\n”, *(ptr+1)); // pointer moves to next index then dereferences : goes from 40 to 60, then references the number to 60.
so STDOUT will get. 21, 20 , 60
Using pointer arithmetic, it is easy to compute the address of any array element in memory
Pointers can be compared if they point to the same memory element, then the two pointers are equal , does not need to be dereferenced to make this comparison)
Remember there is always restrictions of accessing memory so segfaults must be in periphery /caution
Restriction on memory access
Not all memory is accessible by our program
C doesn’t check, but the operating system will.
Processor are a collection of REGISTERS. They will/have access and look for the address in the memory. The MEMORY will contain data/arrays/etc. and when it is dereferenced it will send the data back to the processor
Processor to Memory : address
Memory to Processor: Data
??
User space is from 0 to 2^31 -1
Operating System space (kernel) is 2^31 to 2^32-1
int * p, arr[5]; // declaration
arr = 20, NULL, NULL, NULL, NULL
What will cause an error in compilation?
i) p = arr +5;
ii) arr = p +1;
arr = p+1;
arr is currently point to first index of array arr. So setting it equal to something can’t be done without the dereference operator. Inaddititon, it can’t be changed with the syntax provided.
Formally, ‘Assignment to epression with array type’
Arr is the name for the address of the array.
p=arr+5 will be fine at compile time, but when run, it wil lead to runtime error of segfault
int * p, arr[5]; // declaration
p=arr+5;
*p=0;
What will happen at execution?
Results in seg fault since memory location being accessed is out of bounds
How does the pointer to pointers work (case study, main function parameters:
int main (int argc, char ** argv){ .... }
argv[ ] is an array holding a series of pointers (no data values) Accessing each array index will allow user to access a specific string in the command line. Thus, argv[0] returns a pointer to the program executable name entered in command line.
argv[1] is the pointer to the string following program name
etc. etc.
example:
% ./a.out hey there
argv[0] is a pointer pointing to ./a.out, which is a string/char arrray
argv[1] is a pointer pointing to the string/char array “hey”
argv[2] is a pointer pointng to the string/char array “there”
argc is the integer 3
**argv can be also written as *argv[ ]
int main (int argc, char ** argv){ .... }
% ./a.out how are you?
What is *argv[ 3 ] ?
This will return the first character in the fourth string ‘y’
if using argv [3 ], then you get ‘you’
argv[0] will return
./a.out
argv[1] will return
how
argv[2] will return
are
*argv[0] will return
.
*argv[1] will return
h
*argv[2] will return
a
int main (int argc, char **argv){ printf("%c\n", *argv[3] ); printf("%c\n", **(argv+3) ); printf("%c\n", argv[3][ 2 ] );
}
will print:
‘y’
‘y’
‘u’
int main (int argc, char **argv){ printf("%s\n", argv[3] );
}
will print:
“you”
**argv
Above is an array of pointers
- argv is a pointer
**argv should be an array of pointers if using that notation
Pointer - Pointer will give how many elements are between the two pointers in the array.
Cann be useful for counting
Can not add two pointers, just substract
#include int main(int argc, char **argv){ int *p; int arr4[4]; int a; int b; p = arr4; a = 100; *p++ = 1; // write arr4[0] *p++ = 2; *p++ = 3; *p++ = 4; *p++ = 5; printf("%d\n", a); }
What will happen?
No compile error, maybe a runtime erorr, but not compiletime error.
What will happen is access memory outside of arr4.
- p++ = 1; // write arr4[0]
- p++ = 2;
- p++ = 3;
- p++ = 4;
- p++ = 5;
The above lines of code sets the pointer and moves to the next index.
if add *p++=6;
then now a=6, b=5
what is happening is that ‘a’ and ‘b’ are stored below arr4 when “bumping into” b and a, it overwrites the data in a nd b when pointer is incrementing
This is an example “buffer overflow” security issue.
int arr[ ] = {1, 2, 3, 4};
int * ptr = &(arr[0]);
int x = *(ptr++);
int y = *(++ptr);
printf(“x: %d, y: %d”, x, y);
what is printed:
x: ___, y: ____
x: 1 y: 3
int arr[ ] = {1, 2, 3, 4};
int * ptr = &(arr[0]); // ptr will point to address of arr[0]
int x = *(ptr++); //variable x is declared and given the value of 1 since ptr is at arr[0] , after updating x it will point to arr[1]
int y = *(++ptr); // ptr moves to the next index of arr[2] then is dereferenced, giving y the value of 3
printf(“x: %d, y: %d”, x, y);
int arr[] = {1, 2, 3};
int * ptr = &(arr[1]);
*ptr++ = 10; printf("arr[0] = %d, ", arr[0]); printf("arr[1] = %d, ", arr[1]); printf("arr[2] = %d", arr[2]);
what is:
arr[0]
arr[1]
arr[2]
what is:
arr[0] = 1 arr[1] = 10 arr[2] = 3
int arr[] = {1, 2, 3}; //declars arr with values
int * ptr = &(arr[1]); // ptr points to arr[1]
*ptr++ = 10; assign arr[1] to 10 from 2 and now point to arr[2] printf("arr[0] = %d, ", arr[0]); printf("arr[1] = %d, ", arr[1]); printf("arr[2] = %d", arr[2]);
int arr[] = {9, 4, 6, 2};
int * ptr = &(arr[3]);
ptr = ptr - 3;
ptr += 2;
printf(“%d”, *ptr);
what s printed in last line ?
Prints : 6
int arr[] = {9, 4, 6, 2}; // declares array
int * ptr = &(arr[3]); // initialize and point to arr[3] which is 2
ptr = ptr - 3; // ptr is updated to point to 3 indices back to arr[0]
ptr += 2; //ptr is updated to point to arr[2]
printf(“%d”, *ptr);
int arr[] = {1, 2, 3, 4};
int * ptr = &(arr[0]);
ptr += *ptr;
ptr += *ptr;
printf(“%d”, *ptr);
what is printed?
Prints 4
int arr[] = {1, 2, 3, 4}; // declares array with values
int * ptr = &(arr[0]); // points ptr to arr[0]
ptr += *ptr; // updates ptr with the value of ptr = ptr + *ptr, which is ptr = ptr + 1 arr[1], so now ptr is now pointing to arr[1]
ptr += *ptr; // ptr with ptr = ptr + 2, which ptr is now pointing to arr[3]
printf(“%d”, *ptr);
prints 4
Pass by Value
All arguments in C are passed by value and follow pass by value semantics: the parameter gets a copy of its argument value, and modifying the parameter’s value does not change its argument’s value. When passing base type values, like the value of an int variable, the function parameter gets a copy of its argument value (the specific int value), and changing the int value stored in the parameter cannot change the int value stored in its argument.
In pass-by-pointer, the parameter still gets the value of its argument, but it is passed the value of an address. Just like in passing base types, changing a pointer parameter’s value will not change its argument’s value (i.e. assigning the parameter to point to a different address will not change the argument’s address value). However, by dereferencing a pointer parameter, the function can change the contents of memory that both the parameter and its argument refers to; through a pointer parameter, a function can modify a variable that is visible to the caller after the function returns.
if a line of code is the following what is done?
*input = 100;
// the location input points to (x’s memory) is assigned 100
changing whatever varialbe is at the address ptr is pointing to to change to 100
int change_value(int *input);
int main() { int x; int y;
x = 30; y = change_value(&x); printf("x: %d y: %d\n", x, y); // prints x: 100 y: 30 return 0; }
int change_value(int *input) { int val; val = *input; if (val < 100) { *input = 100; } else { *input = val * 2; } return val; }
what is the output?
output is
x:100 y: 30
int change_value(int *input);
int main() { int x; int y;
x = 30; y = change_value(&x); printf("x: %d y: %d\n", x, y); // prints x: 100 y: 30 return 0; }
/* * changes the value of the argument * input: a pointer to the value to change * returns: the original value of the argument */ int change_value(int *input) { int val;
val = *input; /* val gets the value input points to */
if (val < 100) { *input = 100; /* the value input points to gets 100 */ } else { *input = val * 2; }
return val; }
Dynamic Memory Allocation
Memory allocation use pointers to dynamically allocate memory. When requesting more memory, pointer variables are used to store the address of dynamically allocated space. Programs often allocate memory dynamically to tailor the size of an array for a particular run.
Dynamically allocating memory allows:
- Do not know the size of arrays or other data structures until runtime (e.g. the size depends on user input).
- Need to allow for a variety of input sizes (not just up to some fixed capacity).
- Want to allocate exactly the size of data structures needed for a particular execution (don’t waste capacity).
- Grow or shrink the sizes of memory allocated as the program runs, reallocating more space when needed and freeing up space when it’s no longer necessary.
Heap memory
Every byte of memory in program’s memory has assoicated address.
Global variables are in the data region, and local variables are in the stack. Dynamically allocated memory is in the HEAP.
Stack and heap grow at runtime (as functions are called and returned, dynamically allocated memory is allcoated and freed) and are far from the actually memory where the program runs
When memory is requested, the space is allocated and the address of that memory is returned to a pointer variable.
Memory allocation model
Memory for operating system, code, data grow from the “bottom” and on top of each other, while the memory of the stack grows from the end towards the beginning to the heap. The heap memory and stack memory grows towards each other as they increase.
Heap memory is anonymous memory, where “anonymous” means that addresses in the heap are not bound to variable names. Declaring a named program variable allocates it on the stack or data parts of program memory. A local or global pointer variable can store the address of an anonymous heap memory location (e.g. a local pointer variable on the stack can point to heap memory), and dereferencing such a pointer enables a program to store data in the heap.
Malloc and free are part of standard library (stdlib)
general form for calling malloc:
malloc(sizeof(int));
The malloc function returns the base address of the allocated heap memory to the caller (or NULL if an error occurs).
malloc will always return. a void * type (void pointer). It is safer to always cast the pointer type when calling malloc.
(char*)malloc(sizeof(char));
free( )
When a program no longer needs the heap memory it dynamically allocated with malloc, it should explicitly deallocate the memory by calling the free function.
malloc allocates a few bytes as header to buffer the space it allocates to programs
set the pointer to NULL after free to ensure pointer is “decommissioned”
That’s because malloc not only allocates the requested memory bytes, but it also allocates a few additional bytes right before the allocated chunk to store a header structure. The header stores metadata about the allocated chunk of heap space, such as the size. As a result, a call to free only needs to pass the address of heap memory to free. The implementation of free can get the size of the memory to free from the header information that is in memory right before the address passed to free.
Note that while malloc returns a pointer to dynamically allocated space in heap memory, C programs store the pointer to heap locations on the stack.
..
Arrays and Pointers have commonalities (and some differences)
• Pointers are an efficient means to traverse arrays
..
Functions help us with problem decomposition
• C is pass by value
• However, pointers allows us to mimic some pass by reference behavior (e.g.,
you can change the values of primitives through a function)
..
int y , *x;
x = &y;
what is happening in this code?
a pointer contains the addres of a variable
” * “ has high precedence
& means get the address of the variable
&y reutrns the address of y (not its value
x is a pointer to an int type and so its is compatible with &y
&y is not an integer
*x =5;
what is happening?
x is a pointer and since *x is on the Lvalue side it is changing whatever address x is pointed to, to change to 5.
only pointers can store address of variables
what is happening?
int *p1, *p2, x;
p1 = &x;
p2 = p1;
int *p1, *p2, x; // variables declared, given names
p1 = &x; // p1 is given the address (pointing to) of variable x in memory
p2 = p1; //p2 is given the same address that p1 has. p2 copies the value/address that p1 has. this address it copies is the address of x.
Thus in a memory model p1 points to x and p2 is pointing to x.
p2 is not pointing to p1.
this is valid but confusing:
*p * *p
..