在头文件和 C 文件中分解大型 C 程序



我必须将以下代码分解为以下文件:main.c,student.c,students.h,mergesort.c,mergesort.h,aux.c和aux.h。然后,我必须制作一个生成文件来编译所有内容。该程序是在链表上实现的合并排序。我已经分离了代码,但我不知道在头文件和包含指令方面该怎么做,更不知道如何创建 makefile。我需要为头文件包含哪些内容,以及我需要在 C 文件中包含哪些内容?例如,如果 mergesort.c 使用的是 students.c 中的函数,我是否必须在 mergesort.c 中包含 students.h?以下是原始程序的代码:

#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 studentn");
    printf("2: Search for a student by numbern");
    printf("3: Delete a student by numbern");
    printf("4: Display all studentsn");
    printf("5: Sort students by numbern");
    printf("0: Exitn");
    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: %dn", 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 studentn");
  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: %sn", 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] = '';
  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();
}

标头将包含相关代码部分的类型定义和函数声明。 注意,如果用户代码(主要是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 */

源文件将包含在标头中声明的函数的实现。 源文件将包含相关的标头。 不需要了解给定结构类型的代码部分不需要包含声明该结构类型的标头。

大纲生成文件可以很简单:

FILES.c = main.c student.c mergesort.c aux.c
FILES.o = ${FILES.c:.c=.o}
all: students
students: ${FILES.o}
    ${CC} ${CFLAGS} -o $@ ${FILES.o} ${LDFLAGS} ${LDLIBS}
students.o:  students.h
mergesort.o: mergesort.h
aux.o:       aux.h

由于make知道如何从xyz.c构建xyz.o,因此您无需指定这些依赖项。 您应该声明main.c使用的标头(因此您需要一行例如 main.o: students.h mergesort.h aux.h ,但您尚未指出正确的内容(。

最新更新