c revision
recommended listening for this post is cirnos perfect math class. these questions are a bit tricky and should test your knowledge well for the upcoming test.

question 1
what will the following code output?
int main(void) {
char c = 'a';
printf("%d", c);
return 0;
}
explanation: this is about format specifiers. %d is the format specifier for an integer, so when we pass the char a into the format specifier, it gets converted into its integer representation (aka its ascii code, 97).
question 2
what will the following code output?
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int a;
int b = &a;
int c = a + b;
printf("%d: ", c);
return 0;
}
explanation: an integer and a pointer to an integer are two different things and cannot be implicitly cast from one to the other. we can do int b = (int)&a, but this results in its own problems.
question 3
what will the following code output?
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int a = 0.1337;
float b = (float) a;
printf("%lf", a);
}
explanation: this one’s about truncation, the initial bug is in the first line int a = 0.1337;, an int cannot have a decimal value so it gets rounded down to 0. note that option 2 is wrong because we’re still printing it as a float w/ the %lf specifier.
question 4
select the correct way to malloc() for 10 Birds in the following code:
typedef struct {
char *name;
float wingspan;
} Bird;
int main(void) {
...
return 0;
}
explanation: the syntax for malloc() is that it takes a single param size_t size, that rules out the first option. malloc() also returns a pointer - the third option initializes it as an instance of the Bird struct, so that’s out. finally, we’re initialising a pointer to a contiguous array of Bird structs, so we need the actual size of the Bird structs and not the size of their pointers.
question 5
what’s the size of the Bird struct?
typedef struct {
char *name;
float wingspan;
} Bird;
explanation: ok this question is kind of tricky if you don’t know about struct padding, but most structs have to be 8-byte aligned due to compiler optimisations. however you can automatically rule out the first and last options because char* is a pointer to some array (which can be dynamically sized ofc), and pointers are always the same size. the last option is also wrong because a float is always the same size (given you’re using the same compiler for everything).
question 6
after this finishes execution, what will the contents of rawr.txt be (assuming it starts off blank)?
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fptr = fopen("rawr.txt", "r");
fprintf(fptr, "meow meow\n");
return 0;
}
explanation: it’ll just fail silently. ofc, the compiler doesn’t actually do a check to see if the file exists at compiletime, that’s crazy.
optional info so programs will actually segfault if they try to write to read only pages of memory, such as a binary’s Global Offset Table when the program is compiled w/ full Relocation Read-Only. this is relevant in the beautiful field of binary exploitation, which i dearly love, but is absolutely beyond the scope of a first year C class. please message me if you’d love to learn more
question 7
which of the following commands cannot be used to get input from stdin?
explanation:
fgets() reads from a FILE* ptr, and stdin is a FILE* ptr. read() reads from file descriptors, and stdin is also a file descriptor. getc() takes an argument for a FILE* ptr. the only thing here is strstr(), which is essentially python’s .find() method for strings. either way, strstr() can’t read from file pointers or file descriptors, just compare two strings.
question 8
what is the output of the following program? (assume long is 64-bit, and assume we’re on a 64-bit machine too)
#include <stdio.h>
#include <stdlib.h>
int main() {
int a = 10;
long b = (long)&a;
int c = *(int*)b;
printf("%ld %ld %ld\n", a, b, c);
return 0;
}
explanation: in C, this is perfectly valid - we’re casting the value of the pointer to a as if it were a long. we’re on a 64-bit machine so pointers are also 64-bit, the cast works out nice. the important thing here is that you don’t actually lose any information as long as you’re casting back and forth between the same sizes, hence the original value of int a remains at 10.
question 9
what is the output of the following program?
#include <stdio.h>
#include <stdlib.h>
int main() {
char buf[] = "what's so good about picking up the pieces?";
for (int i = 0; buf[i]; i++) {
printf("%c", buf[i]);
}
return 0;
}
explanation: for loops consist of three parts: the initialization, the condition, and the update. typically we see the standard format for a for loop as int i = 0; i<SOME_BOUND; i++ but that condition can really be anything! recall that all strings (char bufs) are nullterminated, and a nullterminator is just a 0 byte which is falsy.
question 10
what is the output of the following program?
#include <stdio.h>
#include <stdlib.h>
int main() {
char c = 'a';
while (c <= 'g') {
c = (c+1)^0x20;
printf("%c", c);
}
return 0;
}
explanation: ok yeah soz this is really tricky. we know that chars are just ints, but lowercase chars are also greater than uppercase chars, so when the xor 0x20 flips the case, the loop doesn’t terminate. we also have to keep in mind that the loop modifies the char BEFORE printing the string, which is why the initial ‘a’ value doesn’t get printed. finally, the conditional is c <= 'g', NOT c < g; so if c == 'g' then the while loop still continues.
question 11
which of the following choices for b[] would not result in the program outputting 1?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int are_the_same(char* a, char* b, int size) {
return (strncmp(a, b, size) == 0);
}
int main() {
char a[7] = "rawr\00xd";
char b[] = "...";
printf("%d", are_the_same(a, b, 7));
return;
}
explanation: again, strings are all null terminated. strncmp only checks at MAX the first n bytes (in this case, 7) but if both strings are null terminated before n then it just exits out. in this case, only raw would fail the check because strncmp would try to compare raw’s null terminator with rawr’s last ‘r’ character.</div>
question 12
which of the following correctly explains why this code won’t compile?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
printf("%d", atoi(getc(stdin)));
return 0;
}
explanation: honestly the answer explains it better than i can here. we just have to remember that a char and char* are distinct. also, atoi() returns an integer.
question 13
what is the output of the following program? assume that doesnotexist.txt does not exist.
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fptr = fopen("doesnotexist.txt", "r");
int a = 0;
if (fptr == a) {
puts("yay!");
} else {
puts("awww.");
}
return 0;
}
explanationa null pointer is just the value 0, and you can compare the two perfectly fine. fopen will always return a null pointer when it fails.
question 14
which of the following is an invalid way to populate the name field of the Student struct?
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[16];
int age;
} Student;
int main(void) {
Student* student = malloc(sizeof(Student));
...
}
question 15 (bonus)
what’s wrong with the following program?
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char buf[16];
fgets(buf, sizeof(buf), stdin);
printf(buf);
return 0;
}