K08 Δομές Δεδομένων και Τεχνικές Προγραμματισμού
Κώστας Χατζηκοκολάκης
C programs allocate memory in 2 ways:
malloc
int
s is allocated the moment foo
is called5
, 17
are copied in the allocated memoryvoid foo() {
int a = 5;
int b = 17;
}
int main() {
foo();
}
void foo(int a) {
int b = 17;
}
int main() {
foo(5);
}
&
To see where a variable is stored, use the address-of operator &
We can print it in hex
printf("Memory address of a in hex: %p \n", &a);
void foo(int a) {
int b = 17;
printf("foo &a: %p\n", &a);
printf("foo &b: %p\n", &b);
}
void foo() {
int a = 5;
printf("foo &a: %p\n", &a);
}
void bar() {
int a = 17;
printf("bar &a: %p\n", &a);
}
int main() {
foo();
bar();
}
foo
has not returned yet when bar
is calledvoid bar() {
int a = 17;
printf("bar &a: %p\n", &a);
}
void foo() {
int a = 5;
printf("foo &a: %p\n", &a);
bar();
}
int main() {
foo();
}
They remain allocated until the program finishes
int global = 5;
void foo() {
printf("foo &global: %p\n", &global);
}
int main() {
printf("main &global: %p\n", &global);
foo();
printf("main &global: %p\n", &global);
}
void foo() {
int* p;
}
p
as “pointing to” a
void foo() {
int a;
int* p = &a;
printf("&a: %p\n", &a);
printf("&p: %p\n", &p);
printf(" p: %p\n", p);
}
malloc(size)
(actually easier to understand)int* p = malloc(sizeof(int));
malloc
allocates memory in the heapint* a = malloc(sizeof(int));
printf("&a: %p\n", &a);
printf(" a: %p\n", a);
free(address)
, for some address
previously returned by malloc
free
d memory can be reused (this is what “deallocated” means)int* p1 = malloc(sizeof(int));
int* p2 = malloc(sizeof(int));
free(p2);
int* p3 = malloc(sizeof(int));
printf("p1: %p\n", p1);
printf("p2: %p\n", p2);
printf("p3: %p\n", p3);
void foo() {
int* p = malloc(sizeof(int));
}
free
does not modify the content of any variableint* p = malloc(sizeof(int));
printf("p: %p\n", p);
free(p);
printf("p: %p\n", p);
p = NULL; // καλή πρακτική μετά το free
*
When reading or writing to a variable:
a
, p
, read/write to the memory allocated for a
, p
*p
reads/writes to the memory stored in p
int a;
int* p;
p = &a; // στη μνήμη που δεσμεύτηκε για το p, γράψε τον αριθμό &a
*p = 16; // στη μνήμη που περιέχει το p (δηλαδή στην &a), γράψε τον αριθμό 16
a = *p + 1;
*p = *q; // αριστερό
p = q; // δεξί
void foo(int a, int* p) {
*p = a;
}
int main() {
int a = 1;
foo(52, &a);
}
Will this work?
void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int a = 1;
int b = 5;
swap(a, b);
}
Will this work?
void swap(int* p, int* q) {
int* temp = p;
p = q;
q = temp;
}
int main() {
int a = 1;
int b = 5;
swap(&a, &b);
}
void swap(int* p, int* q) {
int temp = *p;
*p = *q;
*q = temp;
}
int main() {
int a = 1;
int b = 5;
swap(&a, &b);
}
int* foo() {
int* p = malloc(sizeof(int));
*p = 42;
return p;
}
int main() {
int* p = foo();
printf("content of p: %d\n", *p);
free(p);
}
p
containing deallocated memory is dangerous!
*p
has undefined behaviour (typically it makes your PC explode)int* foo() {
int a = 63;
int* p = &a;
return p; // πού δείχνει ο p;
}
int* foo() {
int* p = malloc(sizeof(int));
*p = 42;
free(p);
return p; // πού δείχνει ο p;
}
struct point_2d { // ένα σημείο στον δισδιάστατο χώρο
float x;
float y;
};
int main() {
struct point_2d point; // μία μεταβλητή!
point.x = 1.2; // έχει αρκετό χώρο
point.y = 0.4; // για 2 floats
}
void foo() {
// θα αποδεσμευθεί στο τέλος της κλήσης της foo
struct point_2d point;
// θα αποδεσμευθεί όταν κάνουμε free
struct point_2d* p = malloc(sizeof(struct point_2d));
}
p
is a pointer to a struct:
p->member
is just a synonym for (*p).member
void foo(struct point_2d* p) {
(*p).x = -1.2;
p->y = 0.4;
// Μπορούμε να αντιγράφουμε και ολόκληρο το struct!
struct point_2d point = *p;
point.x = point.y * 2;
*p = point;
}
typedef
typedef int Intetzer; // English style
typedef int Integker; // Γκρικ στάιλ
int main() {
Intetzer a = 1;
Integker b = 2;
a = b; // και τα δύο είναι απλά ints
}
typedef
, common usesSimplify structs
struct point_2d {
float x;
float y;
};
typedef struct point_2d Point2d;
int main() {
Point2d point; // δε χρειάζεται το "struct point_2d"
}
Even simpler:
typedef struct {
float x;
float y;
} Point2d;
typedef
, common uses“Hide” pointers
// list.h
struct list {
...
};
typedef struct list* List;
List list_create();
void list_destroy(List list);
// main.c
#include "list.h"
int main() {
List list = list_create(); // ποιος "pointer";
list_destroy(list);
}
typedef
is highly recommended// Για μια συνάρτηση σαν αυτή
int foo(int a) {
...
}
// Δηλώνουμε τον τύπο ως εξής (το foo αλλάζει σε (*TypeName))
typedef int (*MyFunc)(int a);
int main() {
// Και μετά μπορούμε να αποθηκεύουμε το "foo" σε μια μεταβλητή f
MyFunc f = foo;
f(40); // το ίδιο με foo(40)
}
typedef int (*MyFunc)(int a);
int foo1(int a) {
return a + 1;
}
int foo2(int a) {
return 2*a;
}
int bar(MyFunc f) {
printf("f(0) = %d\n", f(0));
}
int main() {
bar(foo1);
bar(foo2);
}
void*
can store any pointerint* int_p;
float* float_p;
Point2d* point_p;
MyFunc func_p;
void* p;
p = int_p;
p = float_p;
p = point_p;
p = func_p;
int_p = p;
float_p = p;
point_p = p;
func_p = p;
void*
allows to define operations on data of any type// Ανταλλάσσει τα περιεχόμενα των p,q, μεγέθους size το καθένα
void swap(void* p, void* q, int size) {
void* temp = malloc(size); // allocate size bytes
memcpy(temp, p, size); // αντιγραφή size bytes από το p στο temp
memcpy(p, q, size);
memcpy(q, temp, size);
free(temp);
}
int main() {
int a = 1;
int b = 5;
swap(&a, &b, sizeof(int));
float c = 4.3;
float d = 1.2;
swap(&c, &d, sizeof(float));
}
Combine with function pointers for full power!
typedef void* Pointer; // απλούστερο
// Δείκτης σε συνάρτηση που συγκρίνει 2 στοιχεία a και b και επιστρέφει:
// < 0 αν a < b
// 0 αν a == b
// > 0 αν a > b
typedef int (*CompareFunc)(Pointer a, Pointer b);
Pointer max(Pointer a, Pointer b, CompareFunc comp) {
if(comp(a, b) > 0)
return a;
else
return b;
}
#include <string.h>
int compare_ints(Pointer a, Pointer b) {
int* ia = a;
int* ib = b;
return *ia - *ib;
}
int compare_strings(Pointer a, Pointer b) {
return strcmp(a, b);
}
int main() {
int a1 = 1;
int a2 = 5;
int* max_a = max(&a1, &a2, compare_ints);
char* s1 = "zzz";
char* s2 = "aaa";
char* max_s = max(s1, s2, compare_strings);
printf("max of a1,a2: %d\n", *max_a);
printf("max of s1,s2: %s\n", max_s);
}