[go: up one dir, main page]

0% found this document useful (0 votes)
24 views77 pages

L04 C Intro Pointer Memory Manage

The document discusses pointers, arrays, and memory management in C. It covers topics like address vs value, pointer syntax and usage, array declarations, strings as arrays, and outlines for the course.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
24 views77 pages

L04 C Intro Pointer Memory Manage

The document discusses pointers, arrays, and memory management in C. It covers topics like address vs value, pointer syntax and usage, array declarations, strings as arrays, and outlines for the course.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 77

CS 110

Computer Architecture
C Pointers & Array
Instructors:
Siting Liu & Chundong W ng
Course website: https://to st-l b.sist.sh ngh itech.edu.cn/courses/CS110@Sh ngh iTech/
Spring-2023/index.html
School of Inform tion Science nd Technology (SIST)
Sh ngh iTech University

2023/2/6
a
a
a
a
a
a
a
a
a
a
a
Outline

• Pointer
• Array
• Memory Management

2
Address vs. Value
• Consider memory to be a single huge array

Memory

• Each cell of the array has an address Bytes


associated with it

• Each cell also stores some value


• For addresses do we use signed or
unsigned numbers?

• Don’t confuse the address referring to a 4

memory location with the value stored


there

… … … 0x9a 4
0x78 0x56 0x34 0x12
3 2 1 0
3
Pointers
• An address refers to a particular Memory

memory location; e.g., it points


to a memory location

• Pointer: A variable that contains


Bytes

the address of a variable

4 p

Variable X
… … … 0x9a 4
0x78 0x56 0x34 0x12
3 2 1 0
4
Pointer Syntax
• int *p; Memory

– Tells compiler that variable p is the


address of an int
Bytes
• p = &X;
– Tells compiler to assign address of X to p
– & called the “address operator” in this
context
• z = *p;
(assume a 4-byte int)
– Tells compiler to assign value at address 4 p
p to z
– * called the “dereference operator” in
this context
Variable X
• Can point to int/char/struct/function, etc. 0xf0 0xde 0xbc 0x9a 4
0x78 0x56 0x34 0x12
3 2 1 0
5
Creating and Using Pointers
• How to create a pointer:
& operator: get address of a variable
Note the “*” gets used
int *p, x; p ? x ? 2 different ways in this
example. In the
declaration to indicate
x = 3; p ? x 3 that p is going to be a
pointer, and in the
p = &x; p x 3
printf to get the
value pointed to by p.

• How to get a value pointed to?


“*” (dereference operator): get the value that the pointer points to
printf(“p points to value %d\n”,*p);
6
Using Pointer for Writes

• How to change a variable pointed to?


– Use the dereference operator * on the left of assignment operator =

p x 3

*p = 5; p x 5

7
Pointers and Parameter Passing

• C passes parameters “by value”


– Procedure/function/method gets a copy of the parameter, so
changing the copy cannot change the original

void add_one (int x) {


x = x + 1;
}
int y = 3;
add_one(y);

y remains equal to 3

8
Pointers and Parameter Passing

• How can we get a function to change the value held in a


variable?

void add_one (int *p) {


*p = *p + 1;
}
int y = 3;

add_one(&y);

y is now equal to 4

9
Types of Pointers

• Pointers are used to point to any kind of data (int,


char, a struct, etc.)
• Normally a pointer only points to one type (int, char, a
struct, etc.).
– void * is a type that can point to anything (generic
pointer)
– Be careful, use void * sparingly to help avoid program
bugs, and security issues, and other bad things!

10
More C Pointer Dangers
• Declaring a pointer just allocates space to hold the
pointer – it does not allocate the thing being pointed to!
• Local variables in C are not initialized, they may contain
anything (a.k.a. “garbage”)
• What does the following code do?
g in
r kin
void f() w o t s
ve n en
{ o t e o n m
N nvir
int *ptr; e e
Unde ined Behavior *ptr = 5;som
}

11
f
Pointers and Structures
typedef struct { /* dot notation */
int x; int h = p1.x;
int y; p2.y = p1.y;
} Point;
/* arrow notation */
Point p1; int h = paddr->x;
Point p2; int h = (*paddr).x;
Point *paddr;
/* This works too */
p1 = {1,2}; p1 = p2;

12
Pointers in C
• Why use pointers?
– If we want to pass a large struct or array, it’s easier/faster/etc. to
pass a pointer than the whole thing
– In general, pointers allow cleaner, more compact code
• So what are the drawbacks?
– Pointers are probably the single largest source of bugs in C, so
be careful anytime you deal with them
• Most problematic with dynamic memory management—
coming up soon
• Dangling references and memory leaks

13
Why Pointers in C?
• At time C was invented (early 1970s), compilers often didn’t
produce ef icient code
– Computers 100,000 times faster today, compilers better
• C designed to let programmer say what they want code to do
without compiler getting in way
– Even give compilers hints which registers to use!
• Today’s compilers produce much better code, so may not
need to use pointers in application code
• Low-level system code still needs low-level access via pointers

14
f
Course Info
• HW1 due today! HW2 will be available very soon (see piazza
& course webpage). Lab 2 will be available this Friday.

• Find a lab-mate in the same lab session, two students in a


group, and Sunday deadline approaching!
• Lab 1 is available and in this week’s Lab session
• Lab & Discussion (see webpage, this Friday, VMware/
Ubuntu linux, etc.) starts this week.
• Webpage: https://toast-lab.sist.shanghaitech.edu.cn/
courses/CS110@ShanghaiTech/Spring-2023/index.html

• Discussion next week: Venus (for RISC-V), Memory


Management & debug
15
Outline

• Pointer
• Array
• Memory Management

16
C Arrays
• Declaration:
int ar[2];
declares a 2-element integer array: just a block of memory

int ar[] = {795, 635};


declares and initializes a 2-element integer array

• Must specify size (or provide info. that can infer the size)

17
C Strings
• String in C is just an array of characters
char string[] = "abc";
• How do you tell how long a string is?
– Last character is followed by a ‘\0’ (NULL) byte
(a.k.a. “null terminator”) (RTFM)
Finally, the declaration
int strlength(char s[])
{ char s[] = "abc", t[3] = "abc";
int n = 0;
defines ``plain'' char array objects s and t
while (s[n] != 0) whose members are initialized with character
n++; string literals. This declaration is identical to
return n;
} char s[] = { 'a', 'b', 'c', '\0' },
t[] = { 'a', 'b', 'c' };

18
Array Name/Pointer Duality
• Key Concept: Array variable is a “pointer” to the irst (lowest
addressed, i.e., 0th) element
• So, array variables almost identical to pointers
– char *string and char string[] are nearly identical
declarations
– Differ in subtle ways: incrementing, declaration of illed arrays
• Consequences:
– ar is an array variable, but works like a pointer
– ar[0] is the same as *ar
– ar[2] is the same as *(ar+2)
– Can use pointer arithmetic to conveniently access arrays
19
f
f
Array Name/Pointer Duality
• Be really careful!

char string1[] = “abc";


char *string2 = “abc";

• CAN modify string1[*]

• CANNOT modify string2[*]

• CAN access string2 by string2[*]

20
Array Name/Pointer Duality
• Be really careful!

int arr[] = { 3, 5, 6, 7, 9 };
int *p = arr;
int (*p1)[5] = &arr;
int *p2[5];
int *p3(void);

• Read More: C manual 3.5.5 Type names!

21
Changing a Pointer Argument?

• What if want function to change a pointer?


• What gets printed?

void inc_ptr(int *p) *q = 50


{ p = p + 1; }
A q
int A[3] = {50, 60, 70};
int *q = A;
inc_ptr( q);
printf( "q = %d\n",*q); 50 60 70
Pointer to a Pointer
• Solution! Pass a pointer to a pointer, declared as **h

• Now what gets printed? Pointer to pointer to an int

void inc_ptr(int **h) *q = 60


{ *h = *h + 1; } A q
int A[3] = {50, 60, 70};
int *q = A;
inc_ptr(&q); 50 60 70
printf(“*q = %d\n”, *q);
C Arrays are Very Primitive
• An array in C does not know its own length, and its
bounds are not checked!
– Consequence: We can accidentally access off the end
of an array
– Suggestion: We must pass the array and its size to any
procedure that is going to manipulate it
• Out of boundary errors:
– These are VERY dif icult to ind;
Be careful!

24
f
f
Use De ined Constants
• Array size n; want to access from 0 to n-1, so you should
use counter AND utilize a variable for declaration &
incrementation
– Bad pattern
int i, ar[10];
for(i = 0; i < 10; i++){ ... }
– Better pattern
const int ARRAY_SIZE = 10;
int i, a[ARRAY_SIZE];
for(i = 0; i < ARRAY_SIZE; i++){ ... }

• SINGLE SOURCE OF TRUTH


– You avoid maintaining two copies of the number 10
– DRY: “Don’t Repeat Yourself”
25
f
Pointing to Different Size Objects

Memory
• Modern machines are “byte-
addressable”
– Hardware’s memory composed of Byte-addressable
8-bit storage cells, each has a Byte address
unique address
• A C pointer is just abstracted
memory address char *z
• Type declaration tells compiler 8-bit character
stored in one byte
how many bytes to fetch on each
access through pointer short *y
16-bit short stored
– E.g., 32-bit integer stored in 4 in two bytes

8-11
consecutive 8-bit bytes int *x
4-7

3 2 1 0
• Alignment 32-bit integer
stored in four bytes 26
sizeof() operator

• sizeof(type) returns number of bytes in object


– But number of bits in a byte is not standardized
• In olden times, when dragons roamed the earth, bytes
could be 5, 6, 7, 9 bits long
• By de inition, sizeof(char)==1
• Can take sizeof(variable), or sizeof(type)
• We’ll see more of sizeof when we look at dynamic
memory management

27
f
Pointer Arithmetic
pointer + number pointer – number
e.g., pointer + 1 adds 1 to a pointer, used in array access

char *p; int *p;


char a; int a;
char b; int b;
In each, p now points to b
p = &a; p = &a;
p += 1; (Assuming compiler doesn’t p += 1;
reorder variables in memory.
Never code like this!!!!)

Adds 1*sizeof(char) Adds 1*sizeof(int)


to the memory address to the memory address

Pointer arithmetic should be used cautiously


28
Arrays and Pointers
Passing arrays
• Array ≈ pointer to the initial (0th) Really int *array
Must explicitly
pass the size
array element int
a[i]≡(*(a+(i))) foo(int array[],
unsigned int size)
• An array is passed to a function as {
… array[size - 1] …
a pointer }
– The array size is lost!
int
main(void)

• Usually bad style to interchange {


int a[10], b[5];
arrays and pointers … foo(a, 10)… foo(b, 5) …
}
– Avoid pointer arithmetic!

29
Arrays and Pointers
int
foo(int array[],
unsigned int size)
{ What does this print
4
… (32-bit address)?
printf(“%d\n”, sizeof(array));
} ... because array is really
Compiler time operator a pointer (and a pointer is
int architecture dependent, but
main(void) likely to be 8 on modern
{ machines!)
int a[10], b[5];
… foo(a, 10)… foo(b, 5) … What does this print
printf(“%d\n”, sizeof(a)); 40
(32-bit int)?
}

30
Arrays and Pointers

int i; int *p;


int array[10]; int array[10];

for (i = 0; i < 10; i++) for (p = array; p < &array[10]; p++)


{ {
array[i] = …; *p = …;
} }

These code sequences have the same effect!

31
Concise strlen()
int(long) strlen(char *s)
{ char *p = s;
while (*p++)
; /* Null body of while */
return (p - s - 1);
}

What happens if there is no zero character at


end of string?

32
Point past end of array?
• Array size n; want to access from 0 to n-1, but test for exit
by comparing to address one element past the last
member of the array

int ar[10]={},*p, *q, sum=0;


p = &ar[0]; q = &ar[10];
while (p!=q) /* sum = sum+*p; p = p+1*/
sum += *p++;

• C de ines that one element past end of array must be


a valid address, i.e., not causing an error
f
Valid Pointer Arithmetic
• Add an integer to a pointer.
• Subtract 2 pointers (pointed to the same array/object)
• Compare pointers (<, <=, ==, !=, >, >=)
• Compare pointer to NULL (indicates that the pointer 0x0)
Everything else illegal since makes no sense:
• adding two pointers
• multiplying pointers
• subtract pointer from integer
• etc.
Arguments in main()
• To get arguments to the main function, use:
– int main(int argc, char *argv[])
• What does this mean?
– argc contains the number of strings on the command
line (the executable counts as one, plus one for each
argument). Here argc is 5:
% clang -ansi introC_1_1.c -o introC_1_1.out
– argv is a pointer to an array containing the arguments
as strings

35
Example
% clang -ansi introC_1_1.c -o introC_1_1.out
• argc = 5 /* number arguments */
• argv[0] = "clang",
argv[1] = “-ansi",
argv[2] = “introC_1_1.c”,
argv[3] = “-o”,
argv[4] = “introC_1_1.out”,
• Array of pointers to strings
36
Summary
• “Lowest High-level language”
• Use ANSI C89 in class
• => closest to assembler
• Pointers: powerful but dangerous

• Pointer arithmetic and arrays useful but also dangerous

37
Summary
• Pointers and arrays are virtually same
• C knows how to increment pointers
• C is an ef icient language, with little protection
• Array bounds not checked
• Variables not automatically initialized
• (Beware) The cost of ef iciency is more overhead for the
programmer.
“C gives you a lot of extra rope but be careful not to
hang yourself with it!”

38
f
f
CS 110
Computer Architecture
C Memory Management
Instructors:
Siting Liu & Chundong W ng
Course website: https://to st-l b.sist.sh ngh itech.edu.cn/courses/CS110@Sh ngh iTech/
Spring-2023/index.html
School of Inform tion Science nd Technology (SIST)
Sh ngh iTech University

2023/2/6
a
a
a
a
a
a
a
a
a
a
a
C Memory Management
• To simplify, assume one program runs at a time
• A program’s address space contains 4 regions:
Memory Address
(32 bits assumed here)

• stack: local variables inside functions, grows


~ FFFF FFFFhex
stack
downward

• heap: space requested for dynamic data via


malloc(); resizes dynamically, grows upward

• static data: variables declared outside heap


static functions, does not grow or shrink. Loaded
when program starts, can be modi ied. static data
• code (a.k.a. text): loaded when program code
starts, does not change

• 0x0 unwritable/unreadable (NULL pointer)


~ 0000 0000hex

40
f
Where are Variables Allocated?
• If declared outside a function,
allocated in “static” storage
int myGlobal;
• If declared inside function, main() {
allocated on the “stack” int myTemp;
and freed when function
}
returns

• main() is treated like


a function

• For the above two types, the memory management is automatic


• Don’t need to deallocating when no longer using them
• A variable does not exist anymore once a function ends!
41
The Stack
• Every time a function is called, a new “stack
frame” is allocated on the stack

• Stack frame includes:


funcA() { funcB(); }
funcB() { funcC(); }

• Return address (who called me?) funcC() { funcD(); }

• Arguments
• Space for local variables
funcA frame

• Stack frames contiguous blocks of memory; funcB frame


stack pointer indicates start of stack frame

• When function ends, stack frame is tossed off


the stack; frees memory for future stack frames funcC frame
• Details covered later (RISC-V processor) funcD frame
Stack Pointer
42
Stack Animation
• Last In, First Out (LIFO) data structure
stack
main () _main:
sub sp, sp, #48
{ a(0); Stack … … …
} Stack Pointer mov w8, #1234
grows
void a (int m) stur w8, [x29, #-8]
{ b(1); down mov w8, #4321
stur w8, [x29, #-12]
} ldur w8, [x29, #-8]
void b (int n) ldur w9, [x29, #-12]
{ c(2); add w8, w8, w9
… … …
} add sp, sp, #48
void c (int o) ret
{ d(3);
}
void d (int p)
{
}
43
Passing Pointers into the Stack
stack
• It is ine to pass a #define BUFLEN 256
int main() {
buf char array
pointer to stack …
persistent through
load_buf’s execution
space further down. char buf[BUFLEN];
load_buf(buf, BUFLEN); pointer buf

}

• However, it is bad to return a char *make_buf() { stack


pointer to something in the char buf[50];
stackAddr points
return buf;
stack! } to overwritten memory

• Memory will be overwritten int main(){ buf???


when other functions called! …


char *stackAddr = \
So your data would no make_buf(); Carving on the
longer exist, and writes can foo();
moving boat to look
overwrite key pointers,

} for the sword
causing crashes! 44
Solve with slides to come …
f
Managing the Heap
• The heap is dynamic memory – memory that can be allocated, resized, and
freed during program runtime.
• Useful for persistent memory across function calls
• But biggest source of pointer bugs, memory leaks, …
• Large pool of memory, not allocated in contiguous order
• Back-to-back requests for heap memory could result in blocks very far apart
• C supports four functions for heap management:
• malloc() allocate a block of uninitialized memory
• calloc() allocate a block of zeroed memory
• free() free previously allocated block of memory
• realloc() change size of previously allocated block (might move)
• Read-more: http://web.archive.org/web/20030222051144/http://
home.earthlink.net/~bobbitts/c89.txt section 4.10.3 memory management
functions

45
Managing the Heap
• void *malloc(size_t n):
– Allocate a block of uninitialized memory
– n is an integer, indicating size of allocated memory block in bytes
– size_t is an unsigned integer type big enough to “count” memory bytes
– sizeof returns size of given type in bytes, produces more portable code
– Returns void* pointer to block; NULL return indicates no more memory; always
check for return NULL (if (ip))
– Think of pointer as a handle that describes the allocated block of memory;
Additional control information stored in the heap around the allocated block!
(Including size, etc.)
“Cast” operation, changes type of a variable.
• Examples: Here changes (void *) to (int *)
int *ip1, *ip2;
ip1 = (int *) malloc(sizeof(int));
Ip2 = (int *) malloc(20*sizeof(int)); //allocate an array of 20 ints.
Assuming size of objects can
typedef struct { … } TreeNode; lead to misleading, unportable
TreeNode *tp = (TreeNode *) malloc(sizeof(TreeNode));
code. Use sizeof()!

46
Managing the Heap
• void free(void *p):
– Releases memory allocated by malloc()
– p is pointer containing the address originally returned by malloc()
int *ip;
ip = (int *) malloc(sizeof(int));
... .. ..
free((void*) ip); /* Can you free(ip) after ip++ ? */

typedef struct {… } TreeNode;


TreeNode *tp = (TreeNode *) malloc(sizeof(TreeNode));
... .. ..
free((void *) tp);
– When you free memory, you must be sure that you pass the original
address returned from malloc() to free(); Otherwise, system
exception (or worse)!

47
Managing the Heap
• void *realloc(void *p, size_t size):
– Returns new address of the memory block.
• In doing so, it may need to copy all data to a new location.
realloc(NULL, size); // behaves like malloc
realloc(ptr, 0); // behaves like free, deallocates heap block

– Always check for return NULL

int *ip; ip = (int *) malloc(10*sizeof(int));


… … … /* check for NULL */
Keep track of ip = (int *) realloc(ip, 20*sizeof(int));
this, since it
might change. /* contents of first 10 elements retained */
… … … /* check for NULL */
realloc(ip,0); /* equivalent to free(ip); */

48
Summary
• Code, static storage are easy: they never grow or shrink
• Stack space is relatively easy: stack frames are created and destroyed
in last-in, irst-out (LIFO) order, avoid “dangling references"
• Managing the heap is tricky:
• Memory can be allocated/deallocated at any time
• “Memory leak”: If you forget to deallocate memory
• “Use after free”: If you use data after calling free
• “Double free”: If you call free 2x on same memory

49
f
Using Dynamic Memory—Linked List
typedef struct Node node * head = NULL;
head = (node *) malloc(sizeof(node));
{ if(head == NULL){
int val; return 1;
struct Node *next; }
head -> val = 1;
} node; head -> next = NULL;
Create the irst node
The irst node The last node

Data Data Data Data

Ptr to next Ptr to next Ptr to next Ptr to


Node Node Node NULL

Ptr to head
50
f
f
Using Dynamic Memory—Iterate
typedef struct Node void print_list(node *head){
{ node * current = head;
while (current != NULL){
int val; printf("%d\t", current -> val);
struct Node *next; current = current -> next;
} node; }
printf("\n");
}

The irst node

val Data Data Data

Ptr to next Ptr to next Ptr to


head
Node Node NULL

Ptr to current node


51
f
Using Dynamic Memory—Push
typedef struct Node void push_node(node ** head, int val){
node * new_node;
{ new_node = (node *) malloc (sizeof
int val; (node));
struct Node *next; new_node -> val = val;
new_node -> next = *head;
} node; *head = new_node;
printf("Node %d push succeeds!\n",
(*head) -> val);
The irst node }

val Data Data Data

Ptr to next Ptr to next Ptr to


head
Node Node NULL

new_node Ptr to head node


52
f
Using Dynamic Memory—Remove
typedef struct Node int remove_last(node * head) {
int retval = 0;
{
int val; if (head->next == NULL) {
struct Node *next; retval = head->val;
free(head);
} node; return retval;
}

node * current = head;


The irst node while (current->next->next != NULL) {
current = current->next;
}
Data Data Data
retval = current->next->val;
free(current->next);
Ptr to Ptr to current->next = NULL;
NULL NULL printf("%d is removed.\n",retval);
next next return retval;
}

Ptr to cur. node


53
f
How are Malloc/Free implemented?
• Underlying operating system allows malloc library to ask for
large blocks of memory to use in heap (e.g., using Unix sbrk()
call)
• C standard malloc library creates data structure inside unused
portions to track free space

54
Simple Slow Malloc Implementation

Initial Empty Heap space from Operating System

Free Space
Malloc library creates linked list of empty blocks (one block initially)

Object 1 Free
First allocation chews up space from start of free space

Free

After many mallocs and frees, have potentially long linked list of odd-sized blocks
Frees link block back onto linked list – might merge with neighboring free space
55
Faster malloc implementations
• Keep separate pools of blocks for different sized objects
• “Buddy allocators” always round up to power-of-2 sized chunks
to simplify inding correct size and merging neighboring blocks:

56
f
Power-of-2 “Buddy Allocator”
free

used

57
Malloc Implementations

• All provide the same library interface, but can have


radically different implementations
• Uses headers at start of allocated blocks and space in
unallocated memory to hold malloc’s internal data
structures
• Rely on programmer remembering to free with same
pointer returned by malloc
• Rely on programmer not messing with internal data
structures accidentally!

58
Agenda

• C Memory Management
• C Bugs

59
Common Memory Problems

• Using uninitialized values


• Using memory that you don’t own
– Deallocated stack or heap variable
– Out-of-bounds reference to stack or heap array
– Using NULL or garbage data as a pointer
• Improper use of free/realloc by messing with the pointer
handle returned by malloc/calloc
• Memory leaks (you allocated something you forgot to
later free)

60
Using Memory You Don’t Own
• What is wrong with this code?
• Using pointers beyond the range that had been malloc’d
–May look obvious, but what if mem refs had been result of pointer arithmetic that erroneously
took them out of the allocated range?
int *ipr, *ipw;
void ReadMem() {
int i, j;
ipr = (*int) malloc(4 * sizeof(int));
i = *(ipr - 1000); j = *(ipr + 1000);
free(ipr);
}

void WriteMem() {
ipw = (*int) malloc(5 * sizeof(int));
*(ipw - 1000) = 0; *(ipw + 1000) = 0;
free(ipw);
} 61
Faulty Heap Management

• What is wrong with this code?


int *pi;
void foo() {
pi = malloc(8*sizeof(int));

free(pi);
}

void main() {
pi = malloc(4*sizeof(int));
foo();

}

62
Faulty Heap Management

• Memory leak: more mallocs than frees


int *pi;
void foo() {
pi = malloc(8*sizeof(int));
/* Allocate memory for pi */
/* Oops, leaked the old memory pointed to by pi */

free(pi); /* foo() is done with pi, so free it */
}

void main() {
pi = malloc(4*sizeof(int));
foo(); /* Memory leak: foo leaks it */

}

63
Faulty Heap Management

• What is wrong with this code?

int *plk = NULL;


void genPLK() {
plk = malloc(2 * sizeof(int));
… … …
plk++;
}

64
Faulty Heap Management

• Potential memory leak – handle has been changed, do


you still have copy of it that can correctly be used in a
later free?

int *plk = NULL;


void genPLK() {
plk = malloc(2 * sizeof(int));
… … …
plk++;
}

65
Faulty Heap Management

• What is wrong with this code?

void FreeMemX() {
int fnh = 0;
free(&fnh);
}

void FreeMemY() {
int *fum = malloc(4 * sizeof(int));
free(fum+1);
free(fum);
free(fum);
}
66
Faulty Heap Management

• Can’t free non-heap memory; Can’t free memory that


hasn’t been allocated

void FreeMemX() {
int fnh = 0;
free(&fnh);
}

void FreeMemY() {
int *fum = malloc(4 * sizeof(int));
free(fum+1);
free(fum);
free(fum);
}
67
Using Memory You Haven’t Allocated

• What is wrong with this code?

void StringManipulate() {
const char *name = “Safety Critical";
char *str = malloc(10);
strncpy(str, name, 10);
str[10] = '\0';
printf("%s\n", str);
}

68
Using Memory You Haven’t Allocated

• Reference beyond array bounds

void StringManipulate() {
const char *name = “Safety Critical";
char *str = malloc(10);
strncpy(str, name, 10);
str[10] = '\0';
/* Write Beyond Array Bounds */
printf("%s\n", str);
}
69
Using Memory You Don’t Own
• What’s wrong with this code?

char *append(const char* s1, const char *s2) {


const int MAXSIZE = 128;
char result[128];
int i=0, j=0;
for (j=0; i<MAXSIZE-1 && j<strlen(s1); i++,j++) {
result[i] = s1[j];
}
for (j=0; i<MAXSIZE-1 && j<strlen(s2); i++,j++) {
result[i] = s2[j];
}
result[++i] = '\0';
return result;
}

70
Using Memory You Don’t Own
• Beyond stack read/write

char *append(const char* s1, const char *s2) {


const int MAXSIZE = 128; result is a local array name –
char result[128]; stack memory allocated
int i=0, j=0;
for (j=0; i<MAXSIZE-1 && j<strlen(s1); i++,j++) {
result[i] = s1[j];
}
for (j=0; i<MAXSIZE-1 && j<strlen(s2); i++,j++) {
result[i] = s2[j];
}
result[++i] = '\0';
return result; Function returns pointer to stack
memory – won’t be valid after function
}
returns

71
Using Memory You Don’t Own

• What is wrong with this code?

typedef struct node {


struct node* next;
int val;
} Node;

int findLastNodeValue(Node* head) {


while (head->next != NULL) {
head = head->next;
}
return head->val;
} 72
Using Memory You Don’t Own

• Following a NULL pointer to mem addr 0!

typedef struct node {


struct node* next;
int val;
} Node;

int findLastNodeValue(Node* head) {


while (head->next != NULL) {
head = head->next;
}
return head->val;
} 73
Using Memory You Don’t Own

• What is wrong with this code?

int* init_array(int *ptr, int new_size) {


ptr = realloc(ptr, new_size*sizeof(int));
memset(ptr, 0, new_size*sizeof(int));
return ptr;
}

int* fill_fibonacci(int *fib, int size) {


int i;
init_array(fib, size);
/* fib[0] = 0; */ fib[1] = 1;
for (i=2; i<size; i++)
fib[i] = fib[i-1] + fib[i-2];
return fib;
}

74
Using Memory You Don’t Own

• Improper matched usage of mem handles

int* init_array(int *ptr, int new_size) {


ptr = realloc(ptr, new_size*sizeof(int));
memset(ptr, 0, new_size*sizeof(int));
return ptr;
} Remember: realloc may move entire block

int* fill_fibonacci(int *fib, int size) {


int i;
/* oops, forgot: fib = */ init_array(fib, size);
/* fib[0] = 0; */ fib[1] = 1;
for (i=2; i<size; i++)
What if array is moved to
fib[i] = fib[i-1] + fib[i-2];
new location?
return fib;
}

75
Summary
• All data/program is in memory
– Each memory location has an address to use to refer to it and a
value stored in it
• Pointer is a C version (abstraction) of a data address
– * “follows” a pointer to its value
– & gets the address of a value
– Arrays and strings are implemented as variations on pointers
• C is an ef icient language, but leaves safety to the programmer
– Variables not automatically initialized
– Use pointers with care: they are a common source of bugs in
programs

76
f
Summary

• C has three main memory segments in which to allocate


data:
– Static Data: Variables outside functions
– Stack: Variables local to function
– Heap: Objects explicitly malloc-ed/free-d.
• Heap data is biggest source of bugs in C code

77

You might also like