2014-12-02 5 views
-2

Мне нужно разбить следующий код на следующие файлы: main.c, student.c, students.h, mergesort.c, mergesort.h, aux.c и aux.h. Затем я должен сделать make-файл, чтобы скомпилировать все это. Программа является объединением, реализованным в связанном списке. Я отделил код, но я не имею ни малейшего представления о том, что делать с заголовками файлов и включать директивы, и даже меньше понять, как создать make-файл. Что мне нужно включить для файлов заголовков и что мне нужно включить в файлы C? В качестве примера, если mergesort.c использует функции от students.c, должен ли я включать students.h в mergesort.c? Вот код оригинальной программы:Разбивка большой программы C в файлах заголовков и файлах C

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

#define NAME_LEN 25 

struct node { 
    int number; 
    char name[NAME_LEN+1]; 
    struct node* next; 
}; 

/* The functions to manage the linked list. The functions prompt the 
    user and read the standard input if needed. */ 
struct node* insert  (struct node* student_list); 
void   print_student (struct node* student); 
void   print_list (struct node* student_list); 
void   search  (struct node* student_list); 
struct node* delete  (struct node* student_list); 
void   delete_list (struct node* student_list); 

/* Merge sort */ 
struct node* mergesort(struct node* student_list); 
struct node* merge (struct node* list1, struct node *list2); 

            /* Auxiliary functions */ 
int read_line(char line[], int len); /* Read at most len characters 
        from the standard input and 
        ignore the rest of the line. */ 
int line_skip(); /* Read the standard input to the end of the line. */ 
int line_copy(); /* Read the standard input to the end of the line 
      and copy to the standard output. */ 
int pause();  /* Ask user to press Enter to continue. */ 

int main() { 
    int option; 
    struct node* student_list = NULL; 

    for (;;) { 
    printf("\n-- OPTIONS MENU -----------------\n"); 
    printf("1: Add a student\n"); 
    printf("2: Search for a student by number\n"); 
    printf("3: Delete a student by number\n"); 
    printf("4: Display all students\n"); 
    printf("5: Sort students by number\n"); 
    printf("0: Exit\n"); 
    printf("\n"); 

    printf("Enter an option: "); 
    if (scanf("%d", &option) != 1) { 
     if (feof(stdin)) break; 
     printf("Invalid option: "); line_copy(); pause(); 
     continue; 
    } 

    /* Read the rest of the line after option number. Usually, it is 
     just one new-line character */ 
    line_skip(); 

    if (option == 0) break; 

    switch(option) { 
    case 1: student_list = insert(student_list); break; 
    case 2: search(student_list);     break; 
    case 3: student_list = delete(student_list); break; 
    case 4: print_list(student_list);    break; 
    case 5: student_list = mergesort(student_list); break; 
    default: 
     printf("Incorrect option: %d\n", option); pause(); 
    } 
    } 

    delete_list(student_list); /* Not necessary in this example */ 
    printf("Bye!\n"); 
    return 0; 
} 

struct node* mergesort(struct node* student_list) { 
    struct node* list1 = student_list; 
    struct node* list2 = student_list; 

    if (student_list == NULL || student_list->next == NULL) 
    return student_list; 

    while ((list2 = list2->next) != NULL && 
     (list2 = list2->next) != NULL) 
    list1 = list1->next; 

    list2 = list1->next; 

    list1->next = NULL ; 
    list1 = student_list; 

    list1 = mergesort(list1); 
    list2 = mergesort(list2); 

    return merge(list1, list2); 
} 

struct node* merge(struct node* list1, struct node* list2) { 
    struct node *list, *prev; 

    if (list1 == NULL) return list2; 
    if (list2 == NULL) return list1; 

    if (list1->number <= list2->number) { 
    list = list1; list1 = list1->next; 
    } else { 
    list = list2; list2 = list2->next; 
    } 

    prev = list; 

    while (list1 != NULL && list2 != NULL) { 
    if (list1->number <= list2->number) { 
     prev->next = list1; 
     list1 = list1->next; 
    } else { 
     prev->next = list2; 
     list2 = list2->next; 
    } 
    prev = prev->next ; 
    } 

    if (list1 != NULL) 
    prev->next = list1; 
    else 
    prev->next = list2; 

    return list; 
} 

struct node* insert(struct node* student_list) { 
    struct node* student = malloc(sizeof(struct node)); 
    /* Why would it be incorrect to use "struct node student;" ? */ 

    if (student == NULL) { 
    printf("Out of memory for a new student!\n"); pause(); 
    return student_list; 
    } 

    printf("\nAdding a new student\n"); 
    printf("Enter student's number: "); 
    if (scanf("%d", &student->number) != 1) { 
    printf("Incorrect student number: "); 
    line_copy(); pause(); 
    free(student); /**/ 
    return student_list; 
    } 
    line_skip();   /* to skip the newline character */ 

    printf("Enter student's name: "); 
    read_line(student->name, NAME_LEN); 

    student->next = student_list; 
    printf("Student %d added.\n", student->number); pause(); 

    return student; 
} 

void print_student(struct node* student) { 
    printf("Number:%3d Name: %s\n", student->number, student->name); 
} 

void print_list(struct node* student_list) { 
    printf("\nStudent List:\n"); 
    while (student_list != NULL) { 
    print_student(student_list); 
    student_list = student_list->next; 
    } 
    pause(); 
} 

void search(struct node* student_list) { 
    int number; 

    printf("Enter student number: "); 
    if (scanf("%d", &number) != 1) { 
    printf("Incorrect student number: "); 
    line_copy(); pause(); 
    return; 
    } 
    line_skip(); 

    while (student_list != NULL && number != student_list->number) 
    student_list = student_list->next; 

    if (student_list == NULL) 
    printf("Not found.\n"); 
    else 
    print_student(student_list); 
    pause(); 
} 

struct node* delete(struct node* student_list) { 
    int number; 
    struct node *prev, *cur; 

    printf("Enter student number: "); 
    if (scanf("%d", &number) != 1) { 
    printf("Incorrect student number: "); line_copy(); pause(); 
    return student_list; 
    } 
    line_skip(); 

    for (cur = student_list, prev = NULL; 
     cur != NULL && cur -> number != number; 
     prev = cur, cur = cur->next) 
    ; 

    if (cur == NULL) { 
    printf("Student not found!\n"); pause(); 
    return student_list; 
    } 

    if (prev == NULL) 
    student_list = student_list->next; 
    else 
    prev->next = cur->next; 

    free(cur); 
    return student_list; 
} 

void delete_list(struct node* student_list) { 
    struct node* temp; 

    while (student_list != NULL) { 
    temp = student_list; 
    student_list = student_list->next; 
    free(temp); 
    } 
} 

/*Auxiliary Function 
int read_line(char line[], int len) { 
    int ch, i = 0; 

    while ((ch = getchar()) != '\n' && ch != EOF) 
    if (i < len) 
     line[i++] = ch; 

    line[i] = '\0'; 

    return i; 
} 

int line_skip() { 
    int ch; 
    while ((ch=getchar()) != '\n' && ch != EOF) 
    ; 
    return ch != EOF; 
} 

int line_copy() { 
    int ch; 
    while ((ch=getchar()) != '\n' && ch != EOF) 
    putchar(ch); 
    putchar('\n'); 
    return ch != EOF; 
} 

int pause() { 
    printf("Press Enter to continue..."); 
    return line_skip(); 
} 

ответ

2

В заголовках будут указаны определения типов и объявления функций для соответствующих разделов кода. Обратите внимание, что если код пользователя (в первую очередь main.c) вызывает только mergesort() и не merge(), то заголовок mergesort.h должен объявить mergesort() только и merge() должна быть статической функцией в mergesort.c, скрытая от остальной части коды. Заголовок должен определять только то, что нужно знать клиентам; детали реализации должны быть скрыты. Не забудьте убедиться, что заголовки являются автономными (поэтому, если mergesort.h должен знать о struct node, он включает заголовок, который объявляет, например, struct node). Также убедитесь, что они идемпотентны (так что запись #include "header.h" дважды не вызовет ошибок компиляции). Это делается с помощью охранников заголовка, таких как:

#ifndef HEADER_H_INCLUDED 
#define HEADER_H_INCLUDED 

…body of header file… 

#endif /* HEADER_H_INCLUDED */ 

Исходные файлы будут содержать реализации функций, объявленных в заголовках. Исходные файлы будут содержать соответствующие заголовки. Части кода, которые не должны знать о данном типе структуры, не должны включать заголовок, объявляющий этот тип структуры.

Контура Makefile может быть простым:

FILES.c = main.c student.c mergesort.c aux.c 
FILES.o = ${FILES.c:.c=.o} 

all: students 

students: ${FILES.o} 
    ${CC} ${CFLAGS} -o [email protected] ${FILES.o} ${LDFLAGS} ${LDLIBS} 

students.o: students.h 
mergesort.o: mergesort.h 
aux.o:  aux.h 

С make знает, как строить xyz.o от xyz.c, вам не нужно указывать эту зависимость. Вы должны объявить заголовки, используемые main.c (так что вам нужна строка, такая как main.o: students.h mergesort.h aux.h, но вы не указали, что правильно).

+0

Большое спасибо за вашу помощь, я действительно застрял в этом. Я просто немного запутался во всем заголовке. Для файла main.c включите ли я все файлы .c, все файлы .h или их обоих? – user3019274

+0

Правило большого пальца: заголовки включены; исходных файлов нет. Иногда вы включаете источник, но это редко (попробуйте найти x-макросы, я не пробовал, поэтому я не уверен, насколько хорош поиск). И иногда продукт отправляется так, что он компилируется как один файл - пример SQLite. Если вы включили весь источник в 'main.c', вам придется переписать файл make. –

+0

А, ок. Это очищает его. Большое спасибо за всю эту помощь. – user3019274

Смежные вопросы