Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Practical C Programming: Structures and Linked Lists

Tech 2

Structure Declaration Methods

There are four common approaches to declaring structure variables in C:

Method 1: Define First, Declare Later

Define the structure type, then declare variables separately:

struct pupil {
    long id;
    char fullname[20];
    char gender;
    float grade;
};  // Type definition ends here

struct pupil candidate1, candidate2;  // Variable declaration

Method 2: Define and Declare Simultaneously

Combine type definition with variable declaration:

struct pupil {
    long id;
    char fullname[20];
    char gender;
    float grade;
} candidate1, candidate2;  // Variables declared with type

Method 3: Anonymous Structure with Direct Declaration

Omit the structure tag when variables are declared immediately:

struct {  // No structure name
    long id;
    char fullname[20];
    char gender;
    float grade;
} candidate1, candidate2;  // Direct variable declaration

Note: This approach prevents subsequent declarations of the same type elsewhere in the program, limiting its practical utility.

Method 4: Type Alias with typedef

Create a type alias for cleaner syntax:

typedef struct pupil Scholar;  // Create alias

struct pupil {
    long id;
    char fullname[20];
    char gender;
    float grade;
};

Scholar candidate1, candidate2;  // Use alias for declaration

Programming Exercises

Exercise 1: Comparing Student Records

Task: Read information for two students (ID, name, and integer score) from standard input, store in structures, and output the details of the student with the higher score.

#include <stdio.h>

typedef struct pupil Scholar;

struct pupil {
    long id;
    char fullname[20];
    int marks;
};

Scholar first, second;

int main() {
    scanf("%ld %s %d", &first.id, first.fullname, &first.marks);
    scanf("%ld %s %d", &second.id, second.fullname, &second.marks);
    
    if (first.marks > second.marks) {
        printf("%ld %s %d", first.id, first.fullname, first.marks);
    } else {
        printf("%ld %s %d", second.id, second.fullname, second.marks);
    }
    
    return 0;
}

Exercise 2: Sorting by Academic Performance

Task: Given information for n students (ID, name, score), output the records sorted in descending order by score.

Solution using Standard Library:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int enrollment_id;
    char fullname[50];
    int marks;
} Learner;

int compare_by_score(const void *first, const void *second) {
    const Learner *alpha = (const Learner *)first;
    const Learner *beta = (const Learner *)second;
    
    if (alpha->marks < beta->marks) {
        return 1;  // Descending order
    } else if (alpha->marks > beta->marks) {
        return -1;
    } else {
        return 0;  // Equal scores maintain relative order
    }
}

int main() {
    int count;
    scanf("%d", &count);
    
    Learner cohort[count];
    for (int i = 0; i < count; i++) {
        scanf("%d%s%d", &cohort[i].enrollment_id, cohort[i].fullname, &cohort[i].marks);
    }
    
    qsort(cohort, count, sizeof(Learner), compare_by_score);
    
    for (int i = 0; i < count; i++) {
        printf("%d %s %d\n", cohort[i].enrollment_id, cohort[i].fullname, cohort[i].marks);
    }
    return 0;
}

Implementing Bubble Sort with Generic Interface:

Standard bubble sort for integers:

void bubble_sort_integers(int *dataset, size_t length) {
    for (size_t iteration = 0; iteration < length - 1; iteration++) {
        int is_sorted = 1;  // Optimistic assumption
        
        for (size_t position = 0; position < length - 1 - iteration; position++) {
            if (dataset[position] > dataset[position + 1]) {
                int temporary = dataset[position];
                dataset[position] = dataset[position + 1];
                dataset[position + 1] = temporary;
                is_sorted = 0;  // Swapping occurred
            }
        }
        
        if (is_sorted) {
            break;  // Early termination if already ordered
        }
    }
}

Generic implementation mimicking qsort signature:

#include <stddef.h>

void byte_swap(char *first, char *second, size_t width) {
    for (size_t offset = 0; offset < width; offset++) {
        char temporary = *first;
        *first = *second;
        *second = temporary;
        first++;
        second++;
    }
}

void generic_bubble_sort(void *base, size_t element_count, size_t element_width,
                        int (*compare)(const void *, const void *)) {
    char *array = (char *)base;
    
    for (size_t outer = 0; outer < element_count - 1; outer++) {
        int swapped = 0;
        
        for (size_t inner = 0; inner < element_count - 1 - outer; inner++) {
            char *current = array + inner * element_width;
            char *next = array + (inner + 1) * element_width;
            
            if (compare(current, next) > 0) {
                byte_swap(current, next, element_width);
                swapped = 1;
            }
        }
        
        if (!swapped) {
            break;
        }
    }
}

Key Implementation Details:

  1. Byte-level Pointer Arithmetic: The base pointer is cast to char* because char pointer arithmetic moves in single-byte increments. Adding width bytes navigates to the next element, regardless of data type.

  2. Element Width Parameter: The swap function requires width to perform byte-by-byte exchange, enabling generic handling of any data structure.

  3. Address Calculation: The expression (char*)base + j * width calculates the address of the j-th element by skipping j blocks of width bytes each.

Exercise 3: Election Vote Counting

Task: Three candidates ("Li", "Zhang", "Sun") are running. Each voter casts one vote. Count and display the total votes for each candidate using structures.

#include <stdio.h>
#include <string.h>

typedef struct {
    char candidate_name[20];
} Ballot;

int main() {
    int voter_count;
    scanf("%d", &voter_count);
    
    Ballot votes[voter_count];
    int li_votes = 0, zhang_votes = 0, sun_votes = 0;
    
    for (int i = 0; i < voter_count; i++) {
        scanf("%s", votes[i].candidate_name);
    }
    
    for (int i = 0; i < voter_count; i++) {
        if (strcmp(votes[i].candidate_name, "Li") == 0) {
            li_votes++;
        } else if (strcmp(votes[i].candidate_name, "Zhang") == 0) {
            zhang_votes++;
        } else if (strcmp(votes[i].candidate_name, "Sun") == 0) {
            sun_votes++;
        }
    }
    
    printf("Li:%d\nZhang:%d\nSun:%d", li_votes, zhang_votes, sun_votes);
    return 0;
}

Exercise 4: Student Information Management

Task: Maintain records for up to 50 students (ID, name, three course scores, total). Implement query, update, and delete operations.

#include <stdio.h>
#include <string.h>

int active_count;

struct academic_record {
    char student_id[20];
    char fullname[20];
    int mathematics;
    int literature;
    int science;
    int aggregate;
};

void display_record(struct academic_record entry) {
    printf("%s %s %d %d %d %d\n", 
           entry.student_id, entry.fullname, 
           entry.mathematics, entry.literature, entry.science, entry.aggregate);
}

void search_by_name(struct academic_record roster[], char *target_name) {
    for (int i = 0; i < active_count; i++) {
        if (strcmp(roster[i].fullname, target_name) == 0) {
            display_record(roster[i]);
        }
    }
}

void remove_by_id(struct academic_record roster[], char *target_id) {
    int found_index = -1;
    
    for (int i = 0; i < active_count; i++) {
        if (strcmp(roster[i].student_id, target_id) == 0) {
            found_index = i;
            break;
        }
    }
    
    if (found_index != -1) {
        for (int i = found_index; i < active_count - 1; i++) {
            roster[i] = roster[i + 1];
        }
        active_count--;
    }
}

void modify_scores(struct academic_record roster[], char *target_id, 
                   int math_score, int lit_score, int sci_score) {
    int found_index = -1;
    
    for (int i = 0; i < active_count; i++) {
        if (strcmp(roster[i].student_id, target_id) == 0) {
            found_index = i;
            break;
        }
    }
    
    if (found_index != -1) {
        roster[found_index].mathematics = math_score;
        roster[found_index].literature = lit_score;
        roster[found_index].science = sci_score;
        roster[found_index].aggregate = math_score + lit_score + sci_score;
    }
}

int main(void) {
    int initial_count, operations;
    struct academic_record class_roster[50];
    
    scanf("%d%d", &initial_count, &operations);
    active_count = initial_count;
    
    for (int i = 0; i < initial_count; i++) {
        scanf("%s%s%d%d%d", class_roster[i].student_id, class_roster[i].fullname,
              &class_roster[i].mathematics, &class_roster[i].literature, &class_roster[i].science);
        
        class_roster[i].aggregate = class_roster[i].mathematics + 
                                    class_roster[i].literature + 
                                    class_roster[i].science;
    }
    
    while (operations--) {
        int operation_type;
        scanf("%d", &operation_type);
        
        char temp_id[20], temp_name[20];
        
        if (operation_type == 1) {
            scanf("%s", temp_name);
            search_by_name(class_roster, temp_name);
        } else if (operation_type == 2) {
            int new_math, new_lit, new_sci;
            scanf("%s%d%d%d", temp_id, &new_math, &new_lit, &new_sci);
            modify_scores(class_roster, temp_id, new_math, new_lit, new_sci);
            
            for (int i = 0; i < active_count; i++) {
                display_record(class_roster[i]);
            }
        } else {
            scanf("%s", temp_id);
            remove_by_id(class_roster, temp_id);
            
            for (int i = 0; i < active_count; i++) {
                display_record(class_roster[i]);
            }
        }
    }
    return 0;
}

Linked List Fundamentals

Dynamic linked lists are constructed by allocating nodes dynamicalyl and connecting them via pointers. The construction process involves:

  1. Creating the initial head node
  2. Iteratively appending new nodes to the tail
  3. Terminating with a NULL pointer in the final node's link field

Key pointer variables in list construction:

  • head: Marks the beginning of the list
  • current: Traverses to the end during insertion
  • new_node: Holds the address of dynamically allocated memory

Creating a Singly Linked List

#include <stdio.h>
#include <stdlib.h>

typedef struct list_node {
    int payload;
    struct list_node *link;
} ListNode;

ListNode* initialize_list(int initial_value) {
    ListNode *head = (ListNode *)malloc(sizeof(ListNode));
    if (head == NULL) {
        fprintf(stderr, "Memory allocation failed\n");
        exit(1);
    }
    head->payload = initial_value;
    head->link = NULL;
    return head;
}

void append_node(ListNode *head, int value) {
    ListNode *fresh = (ListNode *)malloc(sizeof(ListNode));
    if (fresh == NULL) {
        fprintf(stderr, "Memory allocation failed\n");
        return;
    }
    fresh->payload = value;
    fresh->link = NULL;
    
    ListNode *current = head;
    while (current->link != NULL) {
        current = current->link;
    }
    current->link = fresh;
}

void traverse_and_print(ListNode *head) {
    ListNode *current = head;
    while (current != NULL) {
        printf("%d ", current->payload);
        current = current->link;
    }
    printf("\n");
}

int main(void) {
    int node_count, value;
    scanf("%d", &node_count);
    
    scanf("%d", &value);
    ListNode *list_head = initialize_list(value);
    
    for (int i = 1; i < node_count; i++) {
        scanf("%d", &value);
        append_node(list_head, value);
    }
    
    traverse_and_print(list_head);
    return 0;
}

Counting Nodes in a List

size_t count_elements(ListNode *head) {
    size_t tally = 0;
    ListNode *current = head;
    
    while (current != NULL) {
        tally++;
        current = current->link;
    }
    return tally;
}

Reversing a Linked List

Reversing a singly linked list requires three pointers to maintain state during traversal: previous, current, and next.

ListNode* reverse_list(ListNode *head) {
    if (head == NULL || head->link == NULL) {
        return head;
    }
    
    ListNode *previous = NULL;
    ListNode *current = head;
    ListNode *upcoming = NULL;
    
    while (current != NULL) {
        upcoming = current->link;  // Store next node
        current->link = previous;  // Reverse the link
        previous = current;        // Move previous forward
        current = upcoming;        // Move current forward
    }
    
    return previous;  // New head of reversed list
}

Complete Reversal Example:

int main(void) {
    int node_count, value;
    scanf("%d", &node_count);
    
    scanf("%d", &value);
    ListNode *sequence = initialize_list(value);
    
    for (int i = 1; i < node_count; i++) {
        scanf("%d", &value);
        append_node(sequence, value);
    }
    
    printf("Before reversal:\n");
    traverse_and_print(sequence);
    
    ListNode *reversed = reverse_list(sequence);
    printf("After reversal:\n");
    traverse_and_print(reversed);
    
    return 0;
}

Related Articles

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

SBUS Signal Analysis and Communication Implementation Using STM32 with Fus Remote Controller

Overview In a recent project, I utilized the SBUS protocol with the Fus remote controller to control a vehicle's basic operations, including movement, lights, and mode switching. This article is aimed...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.