带有getc的stdin会产生额外的输出,并打开文件导致C

时间:2015-04-28 00:23:38

标签: c segmentation-fault stdout stdin fopen

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

typedef int bool;
#define true 1
#define false 0

#define A 65
#define Z 90
#define a 97
#define z 122
#define NEWLINE 10

int main(int argc, char* argv[])
{
    int noArgReverse();
    int argReverse(int i, char* c[]);
    if (argc == 1){
        if (noArgReverse() == 0)
            return 0;
        else
            return 1;
    }
    if (argc > 1){
        if (argReverse(argc, argv) == 0)
            return 0;
        else
            return 1;
    }
    else{
        fprintf(stderr, "unknown error detected.\n");
        return 1;
    }
}

int noArgReverse()
{
    char charInput[10000];
    int pointerArray[5000];
    int pointerCount = 0;
    bool wordStart = false;
    int indexer;
    int lineLength;
    int parser;
    char currInput;

    pointerArray[0] = 0; // first word would start at 0 be default

    while (currInput != EOF){
        lineLength = 0;
        indexer = 0;
        pointerCount = 0;
        while ((currInput = getc(stdin)) != NEWLINE){
            /*
             * I am implementing a 10,000 char limit, as this seems an
             * unreasonable length.
             */
            if (lineLength == 9999){
                fprintf(stderr, "Line length exceeded 10,000 chars. "
                        "This line and, if in the middle of a word,"
                        "will be split.\n");
                break;
            }

            if (!wordStart){
                if ((currInput >= A && currInput <= Z) || (currInput >= a && currInput <= z)){
                    wordStart = true;
                }
            }

            while (wordStart){
                charInput[lineLength++] = currInput;
                currInput = getc(stdin);
                //if the word has ended
                if ((currInput < A || currInput > Z) && (currInput < a || currInput > z)){
                    wordStart = false;
                    charInput[lineLength++] = '\0';
                    if (pointerCount != 0){ // at least one word has been added
                        ++indexer;
                        pointerArray[indexer] = pointerCount;
                        pointerCount = lineLength;
                    }
                    else //first word of the line to be added
                        pointerCount = lineLength;
                }
            }
        }

        while (indexer >= 0){
            parser = pointerArray[indexer--];
            while (charInput[parser] != '\0')
                fprintf (stdout, "%c", charInput[parser++]);
            fprintf (stdout, " ");
        }
        fprintf (stdout, "\r\n");

        if (lineLength == 0){
            currInput = EOF;
        }
    }
    return 0;
}

int argReverse (int argc, char* argv[])
{
    char charInput[10000];
    int pointerArray[5000];
    int pointerCount = 0;
    bool wordStart = false;
    int indexer;
    int lineLength;
    int parser;
    char currInput;
    FILE *currentFile;

    while (argc > 0){
        currentFile = fopen(argv[argc--], "r");
        while ((currInput = getc(currentFile)) != EOF){
            lineLength = 0;
            indexer = 0;
            pointerCount = 0;
            while (currInput != NEWLINE){
                /*
                 * I am implementing a 10,000 char limit, as this seems an
                 * unreasonable length for a single line.
                 */
                if (lineLength == 9999){
                    fprintf(stderr, "Line length exceeded 10,000 chars. "
                            "This line and, if in the middle of a word, the word, "
                            "will be split.\n");
                    break;
                }

                if (!wordStart){
                    if ((currInput >= A && currInput <= Z) || (currInput >= a && currInput <= z)){
                        wordStart = true;
                    }
                }

                while (wordStart){
                    charInput[lineLength++] = currInput;
                    currInput = getc(currentFile);
                    //if the word has ended
                    if ((currInput < A || currInput > Z) && (currInput < a || currInput > z)){
                        wordStart = false;
                        charInput[lineLength++] = '\0';
                        if (pointerCount != 0){ // at least one word has been added
                            ++indexer;
                            pointerArray[indexer] = pointerCount;
                            pointerCount = lineLength;   
                        }
                        else //first word of the line to be added
                            pointerCount = lineLength;
                    }
                }
            }
        }
        fclose(currentFile);
    }
    return 0;
}

所以对于我的第一个函数,我收到一个错误,我似乎无法在调试时找到底部,或者说,我不知道如何解决。该函数应该从stdin获取输入,并以相反的顺序打印单词(字符应保持顺序,因此“这是一个句子”应该是“句子a是这个”)。很简单。但是,当我提供样本输入时,我得到的输出都是错误的。

输入

This is sample
input for testing

输出:

testing for input sample is This

This

输入有一个返回,但输出在行之间有额外的返回,并且不会分割行。

所以,它不应该在它应该的时候打印换行符,而是在它结束时再次打印第一个输入的单词。

我遇到的第二个问题是第二组代码argReverse函数。打开文件后,在这种情况下我使用test.txt,这是一个简单的文本文件,有几行短语和空行,第一次使用getc会返回一个分段错误。我读到这是一个权限或失败的文件打开,但我不知道该怎么做才能解决这个问题。我试图先打开最后一个文件并从那里开始工作,显然,这应该可以处理多个文件,但我甚至无法打开一个文件。我不知道该怎么做才能解决这个问题。我尝试移动getc循环之外的while,同样的问题。我猜我打开文件时做错了,但我不知道它是什么。

1 个答案:

答案 0 :(得分:2)

关于风格的说明:

bool类型,truefalse<stdbool.h>中定义。

使用'A' 'Z' 'a' 'z' '\n'之类的字符常量而不是硬编码的数字,和/或使用来自isalpha的{​​{1}}等字符分类函数。

“反向”函数在结束时返回0,所以返回任何内容都没有意义。它们应该被声明为返回<ctype.h>。如果他们确实返回了有用的东西,我会从void返回该值(消除main语句)。例如,

if

将大型数组放在堆栈上通常是一个坏主意。 (大是主观的,但我使用2K字节作为经验法则。)对于非重入函数,您可以将数组声明为if ( argc == 1 ) return noArgReverse(); 以使它们脱离堆栈。对于可重入函数,您可以static数组,最后malloc

设计说明:

free函数将读取一行并将其放入缓冲区。无需一次阅读一个角色。

处理命令行参数时,规范循环为

fgets

你的seg-fault的原因是你正在使用int main( int argc, char *argv[] ) { for ( int i = 1; i < argc; i++ ) printf( "argv[%d] is \"%s\"\n", i, argv[i] ); } ,C规范保证argv[argc]。因此,您将NULL传递给NULL。此外,您应始终检查fopen的返回值,因为fopen如果无法打开文件,则会返回fopen

到目前为止,代码中最大的设计问题是重复。你有两个几乎完全相同的功能,这是调试和维护的噩梦,因为每次更改都需要进行两次,并进行两次测试。解决方案是定义一个NULL函数,它将文件指针作为输入。 reverse函数应该负责打开/关闭文件,或者在没有任何参数时传递main

示例代码:

stdin