Week 01 Tutorial Questions
Objectives
- to meet other students doing the course with you
- to refamiliarise yourself with C
- to start thinking about how C programs store data in memory
- to introduce what a MIPS program looks like
-
Class introduction (for everyone, starting with the tutor):
- What is your preferred name (what should we call you?) - feel free to share pronouns if you wish!
- What is your degree and year of study?
- Share a fun fact about yourself!
-
The following snippet of C code declares two variables,
of the variables
s1
ands2
with some subtle differences between them.#include <stdio.h> char *s1 = "abc"; int main(void) { char *s2 = "def"; // ... }
- What does the memory layout of a typical program look like?
- What is a global variable?
- How do they differ from local variables? Where are they each located in memory?
- What is a string literal? Where are they located in memory?
-
What is wrong with the following code?
#include <stdio.h> int *get_num_ptr(void); int main(void) { int *num = get_num_ptr(); printf("%d\n", *num); } int *get_num_ptr(void) { int x = 42; return &x; }
Assuming we still want
get_num_ptr
to return a pointer, how can we fix this code?How does fixing this code affect each variable's location in memory?
-
Consider the following C program:
#include <stdio.h> int main(void) { char str[10]; str[0] = 'H'; str[1] = 'i'; printf("%s", str); return 0; }
What will happen when the above program is compiled and executed?
In particular, what does this look like in memory?
How could we fix this program?
-
Consider the following while loop:
How could we rewrite the above program using a for loop? What subtle difference would there be between the two programs?
#include <stdio.h> int main(void) { int i = 0; while (i < 10) { printf("%d\n", i); i++; } return 0; }
-
In the following program, what are argc and argv? The following program prints number of command-line arguments and each command-line argument on a separate line.
What will be the output of the following commands?
#include <stdio.h> int main(int argc, char *argv[]) { printf("argc=%d\n", argc); for (int i = 0; i < argc; i++) { printf("argv[%d]=%s\n", i, argv[i]); } return 0; }
dcc -o print_arguments print_arguments.c print_arguments I love MIPS
-
The following program sums up command-line arguments.
Why do we need the function atoi in the following program?
The program assumes that command-line arguments are integers. What if they are not integer values?
#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int sum = 0; for (int i = 0; i < argc; i++) { sum += atoi(argv[i]); } printf("sum of command-line arguments = %d\n", sum); return 0; }
-
For each of the following commands, describe what kind of output would be produced:
-
clang -E x.c
-
clang -S x.c
-
clang -c x.c
-
clang x.c
In particular, how do these commands relate to what we will be studying in COMP1521?
You can use the following simple C code as an example:
#include <stdio.h> #define N 10 int main(void) { char str[N] = { 'H', 'i', '\0' }; printf("%s\n", str); return 0; }
-
Extra questions
The following questions are extra content not necessarily needed to cover this week's content.
Your tutor may still choose to cover some of these questions, time permitting.
-
What is
mipsy
(andmipsy_web
), and what do we use them for in COMP1521? -
Without diving into too much detail,
translate the following C program into
MIPS assembler and run it with
1521 mipsy
.Store variable x in register $t0 and store variable y in register $t1.// Prints the square of a number #include <stdio.h> int main(void) { int x, y; printf("Enter a number: "); scanf("%d", &x); y = x * x; printf("%d\n", y); return 0; }
Revision questions
The following questions are primarily intended for revision, either this week or later in session.
Your tutor may still choose to cover some of these questions, time permitting.
-
Consider the following C program:
#include <stdio.h> void print_array(int nums[], int len) { for (int i = 0; i < len; i++) { printf("%d\n", nums[i]); } } int main(void) { int nums[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3}; print_array(nums, 10); return 0; }
This program uses a
for
loop to print out each element in the arrayRewrite this program using a recursive function
-
Consider the following C program skeleton:
int a; char b[100]; int fun1() { int c, d; ... } double e; int fun2() { int f; static int ff; ... fun1(); ... } int g; int main(void) { char h[10]; int i; ... fun2() ... }
Now consider what happens during the execution of this program and answer the following:
Which variables are accessible from within
main()
?Which variables are accessible from within
fun2()
?Which variables are accessible from within
fun1()
?Which variables are removed when
fun1()
returns?Which variables are removed when
fun2()
returns?How long does the variable
f
exist during program execution?How long does the variable
g
exist during program execution?
- C's sizeof operator is a prefix unary operator (precedes its 1 operand) - what are examples of other C unary operators?
- Why is C's sizeof operator different to other C unary & binary operators?
-
Discuss errors in this code:
struct node *a = NULL: struct node *b = malloc(sizeof b); struct node *c = malloc(sizeof struct node); struct node *d = malloc(8); c = a; d.data = 42; c->data = 42;
- What is a pointer? How do pointers relate to other variables?
-
Consider the following small C program:
#include <stdio.h> int main(void) { int n[4] = { 42, 23, 11, 7 }; int *p; p = &n[0]; printf("%p\n", p); // prints 0x7fff00000000 printf("%lu\n", sizeof (int)); // prints 4 // what do these statements print ? n[0]++; printf("%d\n", *p); p++; printf("%p\n", p); printf("%d\n", *p); return 0; }
Assume the variable
n
has address0x7fff00000000
.Assume
sizeof (int) == 4
.What does the program print?
-
Consider the following pair of variables
int x; // a variable located at address 1000 with initial value 0 int *p; // a variable located at address 2000 with initial value 0
If each of the following statements is executed in turn, starting from the above state, show the value of both variables after each statement:
p = &x;
x = 5;
*p = 3;
x = (int)p;
x = (int)&p;
p = NULL;
*p = 1;
If any of the statements would trigger an error, state what the error would be.
- What is a struct? What are the differences between structs and arrays?
-
Define a struct that might store information about a pet.
The information should include the pet's name, type of animal, age and weight.
Create a variable of this type and assign information to it to represent an axolotl named "Fluffy" of age 7 that weighs 300grams.
-
Write a function that increases the age of fluffy by one and then increases
its weight by the fraction of its age that has increased. The function is
defined like this:
void age_fluffy(struct pet *my_pet);
e.g.: If fluffy goes from age 7 to age 8, it should end up weighing 8/7 times the amount it weighed before. You can store the weight as an int and ignore any fractions.
Show how this function can be called by passing the address of a struct variable to the function.
- Write a main function that takes command line input that fills out the fields of the pet struct. Remember that command line arguments are given to our main function as an array of strings, which means we'll need something to convert strings to numbers.
-
Consider the following (working) C code to trim whitespace from both ends of a string:
// COMP1521 21T2 GDB debugging example #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <assert.h> void trim(char *str); char **tokenise(char *str, char *sep); void freeTokens(char **toks); int main(int argc, char *argv[]) { if (argc != 2) exit(1); char *string = strdup(argv[1]); printf("Input: \"%s\"\n", string); trim(string); printf("Trimmed: \"%s\"\n", string); char **tokens = tokenise(string, " "); for (int i = 0; tokens[i] != NULL; i++) printf("tok[%d] = \"%s\"\n", i, tokens[i]); freeTokens(tokens); return 0; } // trim: remove leading/trailing spaces from a string void trim(char *str) { int first, last; first = 0; while (isspace(str[first])) first++; last = strlen(str)-1; while (isspace(str[last])) last--; int i, j = 0; for (i = first; i <= last; i++) str[j++] = str[i]; str[j] = '\0'; } // tokenise: split a string around a set of separators // create an array of separate strings // final array element contains NULL char **tokenise(char *str, char *sep) { // temp copy of string, because strtok() mangles it char *tmp; // count tokens tmp = strdup(str); int n = 0; strtok(tmp, sep); n++; while (strtok(NULL, sep) != NULL) n++; free(tmp); // allocate array for argv strings char **strings = malloc((n+1)*sizeof(char *)); assert(strings != NULL); // now tokenise and fill array tmp = strdup(str); char *next; int i = 0; next = strtok(tmp, sep); strings[i++] = strdup(next); while ((next = strtok(NULL,sep)) != NULL) strings[i++] = strdup(next); strings[i] = NULL; free(tmp); return strings; } // freeTokens: free memory associated with array of tokens void freeTokens(char **toks) { for (int i = 0; toks[i] != NULL; i++) free(toks[i]); free(toks); }
You can grab a copy of this code as trim.c.
The part that you are required to write (i.e., would not be part of the supplied code) is highlighted in the code.
Change the code to make it incorrect. Run the code, to see what errors it produces, using this command:
gcc -std=gnu99 -Wall -Werror -g -o trim trim.c ./trim " a string "
Then use GDB to identify the location where the code "goes wrong".