Practice, Debugging, and Arrays
Loop tracing · Function review · Reading many values · Array basics
Part 1 — Week 2 Practice Review
We will review last week by doing small exercises first, then comparing against a clean answer.
Problem 1 — Factorial
Practice first
- Trace
factorial(5): write down result after each loop. - Fill the two blanks in the C function below.
- Check the edge case: what should
factorial(0)return?
int factorial(int n) { int result = ____; for (int i = 1; i <= n; i++) { result = result * ____; } return result;}| i | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
| result | 1 | 2 | 6 | 24 | 120 |
Reference answer
#include <stdio.h>int factorial(int n) { int result = 1; for (int i = 1; i <= n; i++) { result *= i; } return result;}int main() { int n; scanf("%d", &n); printf("%d\n", factorial(n)); return 0;}def factorial(n): result = 1 for i in range(1, n + 1): result *= i return resultn = int(input())print(factorial(n))Problem 2 — Reverse Integer
Practice first
- For n = 120030, fill digit, result, and n after each loop.
- Then fill the missing update line in the function.
- Run the same thinking for n = 0.
int reverse_int(int n) { int result = 0; while (n > 0) { int digit = n % 10; result = __________________; n = n / 10; } return result;}| Round | digit | result | n |
|---|---|---|---|
| 1 | 0 | 0 | 12003 |
| 2 | 3 | 3 | 1200 |
| 3 | 0 | 30 | 120 |
| 4 | 0 | 300 | 12 |
| 5 | 2 | 3002 | 1 |
| 6 | 1 | 30021 | 0 |
Reference answer
#include <stdio.h>int reverse_int(int n) { int result = 0; while (n > 0) { int digit = n % 10; result = result * 10 + digit; n /= 10; } return result;}int main() { int n; scanf("%d", &n); printf("%d\n", reverse_int(n)); return 0;}def reverse_int(n): result = 0 while n > 0: digit = n % 10 result = result * 10 + digit n //= 10 return resultn = int(input())print(reverse_int(n))Problem 3 — Primes in a Range
Practice first
- For input
14 20, mark each number as prime or not prime. - For input
8 10, decide why the output is NONE. - Fill the two TODO parts in the C code.
14
NO
15
NO
16
NO
17
YES
18
NO
19
YES
20
NO
int is_prime(int n) { for (int i = 2; i * i <= n; i++) { if (__________) { return 0; } } return 1;}int count = 0;for (int x = L; x <= R; x++) { if (is_prime(x)) { printf("%d\n", x); __________; }}if (count == 0) { printf("NONE\n");}Reference answer
#include <stdio.h>int is_prime(int n) { if (n < 2) { return 0; } for (int i = 2; i * i <= n; i++) { if (n % i == 0) { return 0; } } return 1;}int main() { int L, R; scanf("%d %d", &L, &R); int count = 0; for (int x = L; x <= R; x++) { if (is_prime(x)) { printf("%d\n", x); count++; } } if (count == 0) { printf("NONE\n"); } return 0;}def is_prime(n): if n < 2: return False i = 2 while i * i <= n: if n % i == 0: return False i += 1 return TrueL, R = map(int, input().split())count = 0for x in range(L, R + 1): if is_prime(x): print(x) count += 1if count == 0: print("NONE")Part 2 — Slow Down and Debug
This week is intentionally slower. Before learning more syntax, we need to make loops, conditions, functions, and input/output feel reliable.
1. The workflow for every problem
When a program does not work, the problem is usually not the C language itself. It is usually one of these: the input was misunderstood, the loop range is wrong, a variable was not initialized, or the output format does not match.
1. Read
What is given?
2. Trace
Try one sample by hand.
3. Code
Write the smallest loop.
4. Test
Check edge cases.
2. Trace before you code
Tracing means writing down how variables change after each loop iteration. This catches many mistakes before the compiler does.
int n = 5;int result = 1;for (int i = 1; i <= n; i++) { result = result * i;}| i | Before update | After update |
|---|---|---|
| 1 | result = 1 | result = 1 |
| 2 | result = 1 | result = 2 |
| 3 | result = 2 | result = 6 |
| 4 | result = 6 | result = 24 |
| 5 | result = 24 | result = 120 |
3. Common beginner bugs
| Bug | Symptom | Fix |
|---|---|---|
| int sum; | The answer changes randomly. | int sum = 0; |
| i < n | The last value is missing. | i <= n |
| scanf("%d", n) | The program may crash. | scanf("%d", &n) |
| if (x = 0) | The condition is not comparing. | if (x == 0) |
Part 3 — Function Review
1. What should go into a function?
A function should do one useful job. In most homework problems, main should handle input/output, and helper functions should handle computation.
return_type function_name(parameter_list) { // compute something return answer;}2. return is not printf
Many beginners print inside every function. That makes the function harder to reuse. Prefer returning the result, then printing it in main.
Hard to reuse
void square(int x) { printf("%d\n", x * x);}Reusable
int square(int x) { return x * x;}print_line, then void may be appropriate.3. Review examples
int is_even(int n) { return n % 2 == 0;}int max2(int a, int b) { if (a > b) { return a; } return b;}int sum_to_n(int n) { int sum = 0; for (int i = 1; i <= n; i++) { sum += i; } return sum;}Part 4 — Array Basics
1. Why do we need arrays?
A variable stores one value. An array stores many values of the same type, using one name and an index.
Without array
int score1 = 80;int score2 = 91;int score3 = 76;int score4 = 88;int score5 = 95;With array
int scores[5] = {80, 91, 76, 88, 95};2. Memory model: contiguous slots
An array is not just a convenient syntax. In C, it is a continuous block of memory. The animation below shows how declaration, indexing, reading, writing, and out-of-bounds access work.
Animated memory model
How int a[5] lives in memory
Current C line
int a[5];
CPU does
reserve stack space
Stack memory
Declare the array
The stack reserves 5 adjacent int slots for a.
Each int takes 4 bytes in this example. The values are not meaningful until we write to them.
Legend
a[i] becomes an address calculation. Reading uses the value stored at that address. Writing changes the value stored there. In C, the compiler does not automatically stop you from using a[5], so the programmer must keep indexes inside bounds.3. Index starts at 0
For an array of length 5, the valid indexes are 0, 1, 2, 3, and 4. There is no index 5.
int scores[5] = {80, 91, 76, 88, 95};printf("%d\n", scores[0]); // 80printf("%d\n", scores[4]); // 95// scores[5] is wrong: valid indexes are 0 to 4.for (int i = 0; i < n; i++), not i <= n.4. Read n values
The most common input pattern for arrays is: first read n, then read n values into the array.
#include <stdio.h>int main() { int n; int a[100]; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } for (int i = 0; i < n; i++) { printf("%d\n", a[i]); } return 0;}n = int(input())a = list(map(int, input().split()))for x in a: print(x)5. Common array computations
Most beginner array problems are still loop problems. The only new idea is that the loop reads from a[i].
int sum_array(int a[], int n) { int sum = 0; for (int i = 0; i < n; i++) { sum += a[i]; } return sum;}int max_array(int a[], int n) { int best = a[0]; for (int i = 1; i < n; i++) { if (a[i] > best) { best = a[i]; } } return best;}int count_at_least(int a[], int n, int threshold) { int count = 0; for (int i = 0; i < n; i++) { if (a[i] >= threshold) { count++; } } return count;}int a[] and int n.Part 5 — Assignments
Requirements
- 3 required problems. Estimated time: 1.5 – 2.5 hours.
- Each problem requires a C version (
.c) and a Python version (.py). - Use loops yourself. In Python, do not use built-in helpers such as
sum,max,min, orlist.indexfor these problems. - For C array problems, assume the maximum array length is 100 and declare arrays like
int a[100];. - These are array problems. Read the values into an array/list first, then pass the array/list to the required functions.
- Output format must match the samples exactly.
You are given n integers. Store them in an array, then print them in reverse order.
This problem forces you to keep the earlier values. If you only print while reading, you cannot print the input backwards.
Input format
First line: one integer n.Second line: n integers.Constraint: 1 ≤ n ≤ 100Output format
One line containing the numbers in reverse order, separated by single spaces.Sample 1
Input
510 20 30 40 50Output
50 40 30 20 10Sample 2
Input
43 3 8 1Output
1 8 3 3Sample 3
Input
142Output
42Required structure
#include <stdio.h>void print_reverse(int a[], int n) { // TODO: print a[n-1], a[n-2], ..., a[0] // Use one space between numbers and one newline at the end.}int main() { int n; int a[100]; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } print_reverse(a, n); return 0;}def print_reverse(a): # TODO: print the list in reverse order passn = int(input())a = list(map(int, input().split()))print_reverse(a)n - 1. A reverse loop usually starts at i = n - 1 and continues while i >= 0.You are given n student scores. Store all scores in an array, compute the average, then print every score below the average in the original order.
This requires a second pass over the same data after the average is known. That is why the array is necessary.
Input format
First line: one integer n.Second line: n integers, the scores.Constraint: 1 ≤ n ≤ 100, 0 ≤ score ≤ 100Output format
Print two lines:avg=AVERAGEbelow=SCORESIf no score is below average, print below=NONE.Sample 1
Input
580 91 76 88 95Output
avg=86.00below=80 76Sample 2
Input
360 60 90Output
avg=70.00below=60 60Sample 3
Input
475 75 75 75Output
avg=75.00below=NONERequired structure
#include <stdio.h>int sum_array(int a[], int n) { // TODO}void print_below_average(int a[], int n, double avg) { // TODO: print "below=" followed by scores below avg. // If there are none, print "below=NONE".}int main() { int n; int scores[100]; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d", &scores[i]); } int total = sum_array(scores, n); double avg = (double) total / n; printf("avg=%.2lf\n", avg); print_below_average(scores, n, avg); return 0;}def sum_array(a): # TODO passdef print_below_average(a, avg): # TODO: print "below=" followed by scores below avg. # If there are none, print "below=NONE". passn = int(input())scores = list(map(int, input().split()))total = sum_array(scores)avg = total / nprint(f"avg={avg:.2f}")print_below_average(scores, avg)NONE.You are given an array and an integer k. Rotate the array left by k positions, then print the result.
Left rotation by 2 changes 10 20 30 40 50 into 30 40 50 10 20.
Input format
First line: one integer n.Second line: n integers.Third line: one non-negative integer k.Constraint: 1 ≤ n ≤ 100, 0 ≤ k ≤ 10000Output format
One line containing the rotated array, separated by single spaces.Sample 1
Input
510 20 30 40 502Output
30 40 50 10 20Sample 2
Input
41 2 3 40Output
1 2 3 4Sample 3
Input
41 2 3 45Output
2 3 4 1Sample 4
Input
19917Output
99Required structure
#include <stdio.h>void left_rotate(int a[], int n, int k) { // TODO: rotate a left by k positions}void print_array(int a[], int n) { // TODO: print the array on one line}int main() { int n, k; int a[100]; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } scanf("%d", &k); left_rotate(a, n, k); print_array(a, n); return 0;}def left_rotate(a, k): # TODO: return a new list rotated left by k positions passdef print_array(a): # TODO: print the list on one line passn = int(input())a = list(map(int, input().split()))k = int(input())a = left_rotate(a, k)print_array(a)k = k % n. One simple method: create a temporary array temp, set temp[i] = a[(i + k) % n], then copy temp back into a.Optional challenge
After finishing the required problems, try rotating the array to the right by k positions instead of left. Think about how the index formula changes.