为什么我的C程序出现分段错误?

时间:2015-04-15 23:22:39

标签: c segmentation-fault

我正在研究C中的字数统计程序。它模拟了Linux / Unix中的wc命令。编译很好,但是当我尝试运行它时,它会给我一个分段错误消息。该程序应该像这样运行:

./mywc -c test.txt
1 2 12 test.txt /* 1 is number of lines, 2 is number of words, 12 is number of chars */

我的代码如下所示:

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

/* Enumerators */
enum { FALSE, TRUE };
enum { STDIN, STDOUT, STDERR };

#define BUFFER_SIZE 4096
#define NAME_SIZE 12
#define MAX_LINES 100000

#define IN 1
#define OUT 0

/* Globals */
char *fileName = NULL; // File name
char tmpName [NAME_SIZE];
int option = FALSE; // Return true if option is provided in command line
int charOption = FALSE; // Return true if -c is provided in command line
int wordOption = FALSE; // Return true if -w is provided in command line
int lineOption = FALSE; // Return true if -l is provided in command line
int standardInput = FALSE;
int c = 0; // Character being scanned
int nl = 0; // Number of lines in file
int nw = 0; // Number of words in file
int nc = 0; // Number of chars in file
int lineStart[MAX_LINES];
int fileOffset = 0;
int fd;

parseCommandLine(int argc, char* argv[]) {
    int i;

    for (i = 1; i < argc; i++) {
      if (argv[i][0] == '-')
        processOptions(argv[i]);
      else if (fileName == NULL)
        fileName = argv[i];
      else
        usageError();
    }
    standardInput = (fileName == NULL);
}

processOptions(char* str) {
    int j;

    for (j = 1; str[j] != '\0'; j++) {
      switch (str[j]) {
        case 'c':
          charOption = TRUE;
          while ( EOF != (str[j] = fgetc(fileName) ) )
            nc++;
          break;
        case 'l':
          charOption = TRUE;
          while (c == fgetc(fileName) != 'Z')
            if (c == '\n')
                nl++;
          break;
        case 'w':
          charOption = TRUE;
          int state = 0;
          while (c == fgetc(fileName) != 'Z') {
            ++nc;
            if (c == '\n')
                nl++;
            if (c == ' ' || c == '\n' || c == '\t')
                state = 0;
            else if (state == 0) {
                state = 1;
                ++nw;
            }
          }
          break;
        default:
          usageError();
          break;
        }
    }
}

usageError() {
    fprintf(stderr, "Usage: mywc -lwc [argv[1]]\n");
    exit(1);
;}

int main(int argc, char *argv[]) {
    int i;

    parseCommandLine(argc, argv);
    processOptions(argv[1]);
    fd = open(fileName, O_RDONLY); /* Open file */

    int flag[3] = {lineOption,wordOption,charOption};
    int stats[3] = {nl,nw,nc};

    if (!option)
        printf("%d %d %d %s\n",nl,nw,nc,fileName);
    else {
        for (i = 0; i < 3; i++) {
            if (flag[i])
                printf("%d ",stats[i]);
        }
        printf("%s\n",fileName);
    }
    return 0;
}

如果我可以获得一些可能导致此错误的帮助,以便我的程序可以正常运行,我将不胜感激。另外,我需要一些关于在我的程序中删除一些警告的提示:

mywc.c: In function ‘parseCommandLine’:
mywc.c:41:15: warning: assignment from incompatible pointer type
      fileName = argv[i];
               ^
mywc.c: In function ‘main’:
mywc.c:96:15: warning: passing argument 1 of ‘open’ from incompatible pointer type
     fd = open(fileName, O_RDONLY); /* Open file */
               ^
In file included from mywc.c:3:0:
/usr/include/fcntl.h:146:12: note: expected ‘const char *’ but argument is of type ‘struct FILE *’
 extern int open (const char *__file, int __oflag, ...) __nonnull ((1));
            ^
mywc.c:102:9: warning: format ‘%s’ expects argument of type ‘char *’, but argument 5 has type ‘struct FILE *’ [-Wformat=]
         printf("%d %d %d %s\n",nl,nw,nc,fileName);
         ^
mywc.c:108:9: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘struct FILE *’ [-Wformat=]
         printf("%s\n",fileName);
         ^

1 个答案:

答案 0 :(得分:1)

首先,程序中可能存在分段错误的原因是您不正确地以文件名作为参数调用fgetc。您需要先打开文件指针,然后将 it 传递给fgetc以读取字符:

FILE *fp = fopen(fileName); // open the file

// ...

int ch  = fgetc(fp); // read a character, using fp instead of fileName

这是导致大多数错误的原因。

此外,所有函数必须在C中具有返回类型。如果您不想返回任何内容,则需要使用返回类型void

// |
// V
void parseCommandLine(int argc, char* argv[]) {
  // ...
}

// |
// V
void processOptions(char* str) {
  // ...
}

最后,您需要先声明或定义一个函数,然后才能使用它。因此,在您的计划中,即使processOptions出现在您的计划parseCommandLine之前,也可以在parseCommandLine内拨打processOptions。在这种情况下,您需要在程序中的processOptions定义之上的某处声明parseCommandLine

void processOptions(char* str); // declaration of processOptions()
                                // notice that there's no function body

void parseCommandLine(int argc, char* argv[]) {  // definition of
                                                 // parseCommandLine()
  // ...
}