General-purpose, imperative, low-level, memory management, compiled
"C was originally developed at Bell Labs by Dennis Ritchie between 1972 and 1973 to make utilities running on Unix" -Wiki
if ( 1 && !0 ){
printf("Non-zero is true\n");
} else {
printf("!0 is 1\n");
}
while ("Is this non-zero?") {
printf("Who thinks yes?\n");
}
int i; /* C99 */
for (; i < 10; i++) {
print("What is wrong with this?\n");
}
/* What might this snipped be used for? */
switch(ast_node->type) {
case INT:
return atoi(ast_node->data);
case PLUS:
int a = process(ast_node->left);
int b = process(ast_node->right);
return a + b
default:
printf("There was an error\n");
exit(1); /* What does exit 1 mean? */
}
C:
B:
if (a) {
goto A;
}
A:
if (b) {
goto B;
}
a = ~a;
b = ~b;
goto C;
What are pointers used for in C?
What are pointers used for in Java?
//stack memory, how many bytes are used?
int a[10] = {42, 0};
//pointer to stack memory
int *pa = a;
//pointer to heap memory
int *b = malloc(sizeof(int)*10);
//pointer to heap memory pointing to pointers,
// how many bytes are used?
int **c = malloc(sizeof(int*)*3);
c[0] = b;
c[1] = b;
c[2] = a+1;
**(c+2) = 72;
printf("What is c[2][0]? %d\n", c[2][0]);
printf("What is c[2][-1]? %d\n", c[2][-1]);
Referencing memory on the stack or heap
Arrays are contiguous blocks of memory. Static 2D Arrays are contiguous, but not Dynamic 2D Arrays
These data structures and how they are represented in memory are important!
int foo(int x, int y, int *z) {
if (x > 0 && y > 0){
*z = x*y;
return SUCCESS;
}
return FAILURE;
}
int main() {
int a = -1;
if (foo(1, 2, &a) == FAILURE) {
return 1;
}
printf("%d\n", a);
return a;
}
How do you return multiple items from a function?
Sometimes one return value is not enough, so pointer as arguments can help receive more data from a function.
What is the Stack?
What is the Heap?
*if you know where to look
/* 1. What is wrong here? */
int *baz(){
int i = 10;
return &i;
}
/* 2. Is this valid? */
int *bar() {
static int i = 5;
return &i;
}
/* 3. Is this valid? */
int *foo() {
void *yeet = malloc(sizeof(double)*10);
return (int *)yeet;
}
/* 4. Is this valid? */
int main() {
char *yeett = (char *)foo();
printf(yeett);
/* 5. Missing something? */
return 0;
}
Why do we care about details like these?
int *foo(int c, int d) {
char e;
void *yeet = malloc(sizeof(c)*d);
/* Stop! */
return (int *)yeet;
}
int main(int argc, char *argv[]) {
int a = 5, 3;
int b = 7;
char *bar = foo((b,a),b);
return 0;
}
High
Low
argv
argc
ret addr
old base
5
7
5
7
ret addr
old base
junk
heap addr