C Structure (struct) Exercises

Eleven problems, from beginner to advanced, that use structures. In most of them the structure definitions and part of the main function are already written, and you write the requested part. Press "Check" to run your code with real gcc on several inputs and see whether the output is correct.

How to use these problems
  1. Read the problem and the sample run, then write your code in the box
  2. Press "▶ Run" to try it with your own input
  3. Press "✔ Check" to test the output against several prepared inputs
  4. Stuck? Open "Hint". Solved it? Compare with "Solution & explanation"
Checking rules
  • Print output exactly as in the sample run. Do not print input prompts such as "Enter a number"
  • Trailing spaces at line ends and trailing blank lines are ignored
  • Your code is saved automatically in this browser

Note: Run and Check send your code to Wandbox, a free external compiler service, and run it with gcc.

11 problems (Beginner 3 · Intermediate 5 · Advanced 3)

Structures (11 problems)

T01 Beginner

Problem 1. A point structure

A structure struct point representing coordinates (members x and y) is defined. Read integers x and y (each between −10000 and 10000) into the members of the structure variable p, print them in the form "(x, y)", and on the next line print the squared distance from the origin (x² + y²).
Sample run (input is underlined)
3 4 (3, 4) Squared distance from origin: 25
Your code
"Run" executes your code with the input above. "Check" tests it against 4 prepared inputs.
Access members with a dot (.), as in p.x. Pass &p.x to scanf, just as with an ordinary variable (. binds more tightly than &, so it means &(p.x)).
#include <stdio.h>

struct point {
    int x;
    int y;
};

int main(void) {
    struct point p;

    scanf("%d %d", &p.x, &p.y);
    printf("(%d, %d)\n", p.x, p.y);
    printf("Squared distance from origin: %d\n", p.x * p.x + p.y * p.y);
    return 0;
}
Explanation: A structure is a type that groups several related values into one. The type name is the whole of struct point, so you cannot leave out struct when declaring a variable (use typedef if you want to omit it). Watch out for the semicolon in }; at the end of a structure definition, which is easy to forget.
T02 Beginner

Problem 2. Data for one student

A structure struct student with a name and a score is defined. Read a name (letters without spaces, 1–19 characters) and a score (0–100) into the structure variable s, and print the name, the score and the result ("Pass" if the score is 60 or more, "Fail" otherwise).
Sample run (input is underlined)
sato 72 Name: sato Score: 72 Result: Pass
Your code
"Run" executes your code with the input above. "Check" tests it against 5 prepared inputs.
The name is a string, so do not put & in front of it, as in scanf("%19s", s.name) (the array name itself is the address of its first element). The score is &s.score.
#include <stdio.h>

struct student {
    char name[20];
    int score;
};

int main(void) {
    struct student s;

    scanf("%19s %d", s.name, &s.score);
    printf("Name: %s\n", s.name);
    printf("Score: %d\n", s.score);
    if (s.score >= 60) {
        printf("Result: Pass\n");
    } else {
        printf("Result: Fail\n");
    }
    return 0;
}
Explanation: A structure member can also be an array (a string). The 19 in %19s means "read at most 19 characters", leaving room for '\0' so the array (20 elements) does not overflow. Also note that you cannot assign to a string member, as in s.name = "sato"; (outside of initialization, use strcpy).
T03 Beginner

Problem 3. Convert a time to seconds

Write a function int to_seconds(struct time t) that receives a structure struct time with hours, minutes and seconds by value and returns the total number of seconds since 00:00:00. The main function is complete (it reads hours (0–23), minutes (0–59) and seconds (0–59) and prints them in the form "hh:mm:ss = N seconds").
Sample run (input is underlined)
1 2 3 01:02:03 = 3723 seconds
Your code
"Run" executes your code with the input above. "Check" tests it against 4 prepared inputs.
One hour is 3600 seconds and one minute is 60 seconds. Inside the function you can use the members as t.h, t.m and t.s.
#include <stdio.h>

struct time {
    int h;
    int m;
    int s;
};

int to_seconds(struct time t) {
    return t.h * 3600 + t.m * 60 + t.s;
}

int main(void) {
    struct time t;
    scanf("%d %d %d", &t.h, &t.m, &t.s);
    printf("%02d:%02d:%02d = %d seconds\n", t.h, t.m, t.s, to_seconds(t));
    return 0;
}
Explanation: A structure can be passed by value just like an int. The function then receives a copy of the whole structure, so even if you write t.h = 0; inside the function, t in main does not change. For a function that only reads, pass by value is enough. %02d means "width 2, padded with 0 if shorter".
T04 Intermediate

Problem 4. Grade table with an array of structures

Data for N students (1 ≤ N ≤ 50) has been read into an array of the structure Student (name and score), named with typedef (the first half of main is complete). Write the rest: print the average score to one decimal place, and on the next line print the name and score of the student with the highest score. If several students share the highest score, print the one who was entered first.
Sample run (input is underlined)
3 sato 72 ito 95 kato 64 Average: 77.0 Top: ito (95 pts)
Your code
"Run" executes your code with the input above. "Check" tests it against 5 prepared inputs.
If you remember the top student by index best rather than by score, you can get the name too. Start with best = 0 and update only when s[i].score > s[best].score (with >=, a later student would replace them).
#include <stdio.h>

typedef struct {
    char name[20];
    int score;
} Student;

int main(void) {
    int n;
    Student s[50];

    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%19s %d", s[i].name, &s[i].score);
    }

    int sum = 0, best = 0;
    for (int i = 0; i < n; i++) {
        sum += s[i].score;
        if (s[i].score > s[best].score) {
            best = i;
        }
    }
    printf("Average: %.1f\n", (double)sum / n);
    printf("Top: %s (%d pts)\n", s[best].name, s[best].score);
    return 0;
}
Explanation: With typedef struct { ... } Student;, you can use just Student as the type name without writing struct. A member of an element of an array of structures is written "array index, then dot", as in s[i].score. For the average, unless you make one side a double as in (double)sum / n, integer division cuts off the decimals.
T05 Intermediate

Problem 5. Update an account through a pointer

Write two functions that receive a pointer to the account structure Account (holder name and balance) and modify it.
• void deposit(Account *a, int amount): increases the balance by amount
• int withdraw(Account *a, int amount): if the balance is sufficient, decreases it by amount and returns 1; otherwise does nothing and returns 0
The main function is complete (it reads the holder name and initial balance, then the number of operations Q and Q lines of "+ amount" (deposit) or "- amount" (withdrawal), and prints the result after each operation). Amounts and the initial balance are between 0 and 100000, and Q is between 1 and 20.
Sample run (input is underlined)
sato 1000 3 + 500 - 2000 - 1500 sato: balance 1500 Insufficient funds sato: balance 1500 sato: balance 0
Your code
"Run" executes your code with the input above. "Check" tests it against 4 prepared inputs.
A member of the structure that pointer a points to is written a->balance (same meaning as (*a).balance). For withdrawal, it is easier to handle the insufficient case first with if (a->balance < amount) return 0;.
#include <stdio.h>

typedef struct {
    char name[20];
    int balance;
} Account;

void deposit(Account *a, int amount) {
    a->balance += amount;
}

int withdraw(Account *a, int amount) {
    if (a->balance < amount) {
        return 0;
    }
    a->balance -= amount;
    return 1;
}

int main(void) {
    Account acc;
    int q;
    scanf("%19s %d", acc.name, &acc.balance);
    scanf("%d", &q);
    for (int i = 0; i < q; i++) {
        char op;
        int amount;
        scanf(" %c %d", &op, &amount);
        if (op == '+') {
            deposit(&acc, amount);
        } else if (!withdraw(&acc, amount)) {
            printf("Insufficient funds\n");
        }
        printf("%s: balance %d\n", acc.name, acc.balance);
    }
    return 0;
}
Explanation: If you pass the structure by value (void deposit(Account a, int amount)), only the copy is modified and the balance in main does not increase. To modify it, pass a pointer, and use . for a structure variable and -> for a pointer to a structure. Writing a.balance is a compile error, and *a.balance is interpreted as *(a.balance), so use (*a).balance with parentheses, or a->balance.
T06 Intermediate

Problem 6. Return the midpoint of two points

Write a function Point midpoint(Point a, Point b) that takes two coordinate structures Point (double members x and y) and returns their midpoint as a structure. The main function is complete (it reads the coordinates of two points x1 y1 x2 y2 (integers between −1000 and 1000) and prints the midpoint to one decimal place).
Sample run (input is underlined)
0 0 3 4 Midpoint: (1.5, 2.0)
Your code
"Run" executes your code with the input above. "Check" tests it against 4 prepared inputs.
Compute each member, as in m.x = (a.x + b.x) / 2;, store it in m, and return it with return m;.
#include <stdio.h>

typedef struct {
    double x;
    double y;
} Point;

Point midpoint(Point a, Point b) {
    Point m = {0.0, 0.0};
    m.x = (a.x + b.x) / 2;
    m.y = (a.y + b.y) / 2;
    return m;
}

int main(void) {
    Point a, b;
    scanf("%lf %lf %lf %lf", &a.x, &a.y, &b.x, &b.y);
    Point m = midpoint(a, b);
    printf("Midpoint: (%.1f, %.1f)\n", m.x, m.y);
    return 0;
}
Explanation: A function can return only one value with return, but a structure lets you return several members together. The returned structure is copied to the caller, so returning the local variable m is fine (this is different from returning the address of a local variable). If the members were int, (0 + 3) / 2 would become 1, so they are double here. To read a double with scanf, use %lf.
T07 Intermediate

Problem 7. Grades in three subjects (array inside a structure)

There is a structure Student with a name and an array of scores for three subjects. Write a function void print_report(const Student *s) that prints one student's total and average. The output is one line per student: "name total average" (average to one decimal place). The main function is complete (it reads N (1 ≤ N ≤ 20) and N lines of "name score1 score2 score3" (scores 0–100), and calls print_report for each student).
Sample run (input is underlined)
2 sato 80 70 92 ito 100 100 99 sato 242 80.7 ito 299 99.7
Your code
"Run" executes your code with the input above. "Check" tests it against 3 prepared inputs.
An element of an array member is written s->score[j]. Compute the total with for (int j = 0; j < 3; j++), and the average with total / 3.0.
#include <stdio.h>

typedef struct {
    char name[20];
    int score[3];
} Student;

void print_report(const Student *s) {
    int total = 0;
    for (int j = 0; j < 3; j++) {
        total += s->score[j];
    }
    printf("%s %d %.1f\n", s->name, total, total / 3.0);
}

int main(void) {
    int n;
    Student st[20];
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%19s", st[i].name);
        for (int j = 0; j < 3; j++) {
            scanf("%d", &st[i].score[j]);
        }
    }
    for (int i = 0; i < n; i++) {
        print_report(&st[i]);
    }
    return 0;
}
Explanation: When a structure is large, it is common to pass it by pointer instead of copying the whole thing by value. If the function only reads it, making it const Student * means an accidental modification is caught as a compile error. Dividing by an integer, as in total / 3, cuts off the decimals, and you would also be passing an int to %.1f, so the output would be wrong.
T08 Intermediate

Problem 8. Is a point inside a rectangle? (nested structures)

A point Point (int x, y) and a rectangle Rect with a bottom-left corner corner (of type Point), width w and height h are defined (a structure inside a structure). Write a function int contains(const Rect *r, Point p) that returns 1 if point p is inside the rectangle (including its edges) and 0 otherwise. Inside means x is at least corner.x and at most corner.x + w, and y is at least corner.y and at most corner.y + h. The main function is complete (it reads the rectangle's x y w h, the number of points Q and Q points, and prints "inside" or "outside" for each point). Coordinates are between −1000 and 1000, and w and h are between 1 and 1000.
Sample run (input is underlined)
0 0 4 3 3 1 1 4 3 5 0 (1, 1): inside (4, 3): inside (5, 0): outside
Your code
"Run" executes your code with the input above. "Check" tests it against 4 prepared inputs.
Nested members are written by chaining them in order. From the pointer r, it is r->corner.x (-> because r is a pointer, . because corner is a structure itself). Join the four conditions with &&.
#include <stdio.h>

typedef struct {
    int x;
    int y;
} Point;

typedef struct {
    Point corner;
    int w;
    int h;
} Rect;

int contains(const Rect *r, Point p) {
    return r->corner.x <= p.x && p.x <= r->corner.x + r->w &&
           r->corner.y <= p.y && p.y <= r->corner.y + r->h;
}

int main(void) {
    Rect r;
    int q;
    scanf("%d %d %d %d", &r.corner.x, &r.corner.y, &r.w, &r.h);
    scanf("%d", &q);
    for (int i = 0; i < q; i++) {
        Point p;
        scanf("%d %d", &p.x, &p.y);
        printf("(%d, %d): %s\n", p.x, p.y, contains(&r, p) ? "inside" : "outside");
    }
    return 0;
}
Explanation: The choice between -> and . is decided by "-> if the left side is a pointer, . if it is a structure". r->corner is a structure of type Point, so what follows is .x. Writing r->corner->x is an error. The result of the comparisons (0 or 1) can be returned directly with return. Edges count as inside, so use <=.
T09 Advanced

Problem 9. Sort a grade table by score

Write a function void sort_by_score(Student *s, int n) that sorts the names and scores of N students (1 ≤ N ≤ 50) from highest score to lowest. Students with the same score must stay in input order. The main function is complete (it reads the data, and after sorting prints "rank name score" one per line; the rank simply counts from 1).
Sample run (input is underlined)
4 sato 72 ito 95 kato 72 abe 88 1 ito 95 2 abe 88 3 sato 72 4 kato 72
Your code
"Run" executes your code with the input above. "Check" tests it against 4 prepared inputs.
In a bubble sort, compare neighbours and swap only when s[j].score < s[j + 1].score. Structures can be assigned as a whole, as in Student tmp = s[j]; s[j] = s[j + 1]; s[j + 1] = tmp;.
#include <stdio.h>

typedef struct {
    char name[20];
    int score;
} Student;

void sort_by_score(Student *s, int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - 1 - i; j++) {
            if (s[j].score < s[j + 1].score) {
                Student tmp = s[j];
                s[j] = s[j + 1];
                s[j + 1] = tmp;
            }
        }
    }
}

int main(void) {
    int n;
    Student s[50];
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%19s %d", s[i].name, &s[i].score);
    }
    sort_by_score(s, n);
    for (int i = 0; i < n; i++) {
        printf("%d %s %d\n", i + 1, s[i].name, s[i].score);
    }
    return 0;
}
Explanation: Assigning one structure to another with = copies all the members (including the character array name inside). If you swap only the scores, names and scores no longer match up, so swap whole structures. If the comparison is <=, students with equal scores are also swapped, and their order is no longer the input order (test 4). A bubble sort that swaps neighbours "only when strictly smaller" is a stable sort, which keeps equal values in their original order.
T10 Advanced

Problem 10. Adding and reducing fractions

There is a structure Fraction with a numerator num and a denominator den. Write the following two functions (the greatest common divisor function gcd is provided).
• Fraction reduce(Fraction f): returns the reduced fraction. Make the denominator positive, and if the numerator is 0, make it 0/1
• Fraction add(Fraction a, Fraction b): returns a + b, reduced
The main function is complete (it reads fractions a and b in the order "numerator denominator numerator denominator" and prints "a/b + c/d = result"; the input fractions are printed as they are, without reducing). Numerators are between −1000 and 1000, and denominators between 1 and 1000. Even if the denominator of the result is 1, print it in the form "2/1".
Sample run (input is underlined)
1 2 1 3 1/2 + 1/3 = 5/6
Your code
"Run" executes your code with the input above. "Check" tests it against 6 prepared inputs.
With a common denominator, a/b + c/d = (a×d + c×b) / (b×d). In add, put this in c and return reduce(c);. In reduce, compute g = gcd(f.num, f.den) and divide the numerator and denominator by g (if the numerator is 0, the gcd is the denominator itself and the result is 0/1).
#include <stdio.h>

typedef struct {
    int num;
    int den;
} Fraction;

int gcd(int a, int b) {
    if (a < 0) a = -a;
    if (b < 0) b = -b;
    while (b != 0) {
        int r = a % b;
        a = b;
        b = r;
    }
    return a;
}

Fraction reduce(Fraction f) {
    if (f.den < 0) {
        f.num = -f.num;
        f.den = -f.den;
    }
    int g = gcd(f.num, f.den);
    f.num /= g;
    f.den /= g;
    return f;
}

Fraction add(Fraction a, Fraction b) {
    Fraction c = {0, 1};
    c.num = a.num * b.den + b.num * a.den;
    c.den = a.den * b.den;
    return reduce(c);
}

int main(void) {
    Fraction a, b;
    scanf("%d %d %d %d", &a.num, &a.den, &b.num, &b.den);
    Fraction c = add(a, b);
    printf("%d/%d + %d/%d = %d/%d\n", a.num, a.den, b.num, b.den, c.num, c.den);
    return 0;
}
Explanation: reduce receives a structure by value and returns a corrected version. The f it receives is a copy, so modifying it does not affect the caller; only the value returned with return f; is used. That is why calling just reduce(c); without using the return value does not reduce anything (write c = reduce(c); or return reduce(c);). With this problem's input the denominators are positive, so the sign adjustment is just a precaution, but when handling negative fractions, deciding to "always keep the denominator positive" keeps the output consistent.
T11 Advanced

Problem 11. Inventory management

Using an array of Item structures (name, unit price, stock), write two functions that process orders.
• Item *find_item(Item *items, int n, const char *name): returns a pointer to the item whose name matches name, or NULL if there is none
• int order(Item *items, int n, const char *name, int qty): processes one order and returns the sales amount. If the item does not exist, print "name: no such item" and return 0. If the stock is less than qty, print "name: insufficient stock (k left)" and return 0. If there is enough stock, reduce it, print "name: qty pcs x price yen = amount yen", and return the amount
The main function is complete (it reads the number of items N (1 ≤ N ≤ 20) and N lines of "name price stock", then the number of orders Q (1 ≤ Q ≤ 20) and Q lines of "name quantity", and finally prints the total sales and the remaining stock of each item). Unit prices are 1–10000, and stock and quantities are 0–100.
Sample run (input is underlined)
3 apple 120 10 milk 200 2 bread 150 5 4 apple 3 milk 5 egg 1 milk 2 apple: 3 pcs x 120 yen = 360 yen milk: insufficient stock (2 left) egg: no such item milk: 2 pcs x 200 yen = 400 yen Total sales: 760 yen apple: 7 left milk: 0 left bread: 5 left
Your code
"Run" executes your code with the input above. "Check" tests it against 4 prepared inputs.
To compare strings, use strcmp(items[i].name, name) == 0, not ==. In find_item, return &items[i] (same as items + i) when it matches. In order, receive it with Item *it = find_item(items, n, name); and use it->stock and it->price.
#include <stdio.h>
#include <string.h>

typedef struct {
    char name[20];
    int price;
    int stock;
} Item;

Item *find_item(Item *items, int n, const char *name) {
    for (int i = 0; i < n; i++) {
        if (strcmp(items[i].name, name) == 0) {
            return &items[i];
        }
    }
    return NULL;
}

int order(Item *items, int n, const char *name, int qty) {
    Item *it = find_item(items, n, name);
    if (it == NULL) {
        printf("%s: no such item\n", name);
        return 0;
    }
    if (it->stock < qty) {
        printf("%s: insufficient stock (%d left)\n", name, it->stock);
        return 0;
    }
    it->stock -= qty;
    int amount = it->price * qty;
    printf("%s: %d pcs x %d yen = %d yen\n", name, qty, it->price, amount);
    return amount;
}

int main(void) {
    int n, q;
    Item items[20];
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%19s %d %d", items[i].name, &items[i].price, &items[i].stock);
    }

    int total = 0;
    scanf("%d", &q);
    for (int i = 0; i < q; i++) {
        char name[20];
        int qty;
        scanf("%19s %d", name, &qty);
        total += order(items, n, name, qty);
    }

    printf("Total sales: %d yen\n", total);
    for (int i = 0; i < n; i++) {
        printf("%s: %d left\n", items[i].name, items[i].stock);
    }
    return 0;
}
Explanation: What find_item returns is a pointer to an element of the array in main, so it->stock -= qty; reduces the real stock. If you copy the structure with Item it = items[i]; and reduce its stock, only the copy changes and the stock in the array stays the same. Reading it->stock when NULL was returned can crash the program, so always check first. items[i].name == name compares addresses, so it does not match even when the strings are the same.

Review these lessons

← Back to all practice problems