在Header文件和C文件中分解大型C程序 [英] Breaking up large C program in Header files and C files

查看:55
本文介绍了在Header文件和C文件中分解大型C程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须将以下代码分解为以下文件:main.c,student.c,students.h,mergesort.c,mergesort.h,aux.c和aux.h.然后,我必须制作一个makefile来编译所有文件. 该程序是在链接列表上实现的合并排序.我已经分离了代码,但是对于头文件和包含指令的处理方式我一无所知,而如何创建makefile则一无所知.我需要为标头文件包括哪些内容,以及我需要在C文件中包括哪些内容?例如,如果mergesort.c使用的是来自students.c的函数,我是否必须在mergesort.c中包括students.h?这是原始程序的代码:

I have to break up the following code into the following files: main.c, student.c, students.h, mergesort.c, mergesort.h, aux.c and aux.h. I then have to make a makefile to compile it all. The program is a mergesort implemented on a linked list. I've separated up the code, but I have no clue as to what to do in terms of headers files and include directives, and even less of a clue as to how to create the makefile. What do I need to include for the headers files, and what do I need to include in the C files? As an example, if mergesort.c is using functions from students.c, would I have to include students.h in mergesort.c? Here's the code for the original program:

#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();
}

推荐答案

您的标头将包含代码相关部分的类型定义和函数声明.请注意,如果用户代码(主要是main.c)仅调用mergesort()而不是merge(),则mergesort.h标头应仅声明mergesort(),而merge()应该是mergesort.c中的静态函数,且已隐藏其余的代码.标头应仅定义客户"需要知道的内容;实施细节应保持隐藏.请记住要确保标头是独立的(例如,如果mergesort.h需要了解struct node,则它包括声明struct node的标头).还要确保它们是幂等的(因此,两次写入#include "header.h"不会导致编译错误).这是通过标题保护程序完成的,例如:

Your headers will contain the type definitions and function declarations for the relevant sections of code. Note that if the user code (primarily main.c) only calls mergesort() and not merge(), then the mergesort.h header should only declare mergesort() and merge() should be a static function in mergesort.c, hidden from the rest of the code. A header should only define what 'clients' need to know; implementation details should be kept hidden. Remember to ensure that the headers are self-contained (so if mergesort.h needs to know about struct node, it includes the header that declares struct node, for example). Also ensure they are idempotent (so writing #include "header.h" twice won't cause compilation errors). This is done with header guards such as:

#ifndef HEADER_H_INCLUDED
#define HEADER_H_INCLUDED

…body of header file…

#endif /* HEADER_H_INCLUDED */

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

The source files will contain the implementations of the functions declared in the headers. The source files will include the relevant headers. Parts of the code that don't need to know about a given structure type shouldn't need to include the header that declares that structure type.

大纲makefile可以很简单:

The outline makefile can be simple:

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这样的行,但是您没有指出正确的地方).

Since make knows how to build xyz.o from xyz.c, you don't need to specify those dependencies. You should declare the headers used by main.c (so you need a line such as main.o: students.h mergesort.h aux.h, but you've not indicated what's correct).

这篇关于在Header文件和C文件中分解大型C程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆