我应该在这个函数中做什么错误检查?

时间:2012-03-29 19:06:51

标签: c

我是一名正在进行中的C程序员,刚开始觉得我做对了。习惯了更高级别的语言(比如C#和Python),我真的很想念我的例外。

以下是我编写的一个函数,目前正用于查看流X个字符。

在此功能中可以进行哪些错误检查以确保它不会制动程序?

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

#include "speek.h"

void speek(char *peek, size_t len, FILE *stream) {

   int i;

   for (i = 0; i < len; i++) {
      peek[i] = fgetc(stream);
      if (feof(stream) || i >= len - 1) {
         // Null terminate the string if stream is EOF or requested number
         // of characters has already been fetched.
         peek[i] = '\0';
         break;
      }   
   }   

   for (i = strlen(peek); i >= 0; i--) {
      ungetc(peek[i], stream);
   }   
}

4 个答案:

答案 0 :(得分:1)

Pavan Manjunath所示,您的程序中存在错误。我可以立即看到的至少另外一个是你不处理文件中的NUL字符:在函数的末尾你使用strlen,它只测量你到第一个NUL字节的刺痛,不一定是你实际阅读的字节数。

但这是一般的错误。您具体询问了错误检查。没有人提到检查错误的最重要的地方:如果读取文件时出错。您应该按照其联机帮助页(首选)中的说明检查fgetc()的EOF返回值,或者之后使用ferror()函数来测试是否在读取文件时发生错误。

根据Thiruvalluvar建议检查peekstream是否为NULL是防御性的,但我不会说必要。那些不应该是NULL。如果是,那就是你的来电者的错,而不是你的。

答案 1 :(得分:1)

我会在阅读字符时检查文件*。

我认为这是一种风格化的东西,但我不会放置我通常打算在循环中发生的事情。

最后,成功读取的字符串应始终以'\ 0'结尾。当发生错误时,我经常被撕裂。如果我知道这个功能是什么,我通常可以选择。

所以,使用你的文件检查方式:

void speek(char *peek, size_t len, FILE *stream) {

   int i;
   for (i = 0; i < len-1 && !feof(stream); i++) {
      peek[i] = fgetc(stream);
   }   

   peek[i] = '\0';

   for (i = strlen(peek)-1; i >= 0; i--) {
      if (ungetc(peek[i], stream) != peek[i]) {
         break;  // I'd return an error, but function is void
      }
   }   
}

如果这不仅仅是一个快速的实验,或者我正在为别人写这个,我可能会使用assert来检查参数(是的,我知道,我仍然这样做(c = getc(...)),我是旧)

#include <assert.h>

int speek(char *peek, size_t len, FILE *stream) {
   assert(peek != NULL);
   assert(len > 0);    /* Could 0 be okay? */
   assert(stream != NULL && !ferror(stream));

   int i;
   int c;
   for (i = 0; i < len-1 && (c=getc(stream)) != EOF; i++) {
      peek[i] = c;
   }   

   peek[i] = '\0';

   if (ferror(stream)) return -1;

   for (int j = i-1; j >= 0; j--) {
      if (ungetc(peek[j], stream) != peek[j]) {
         return -1;
      }
   }  
   return i;   /* I like to return something useful */ 
}

编辑:我试图反映原文,但这不是我做的方式,所以我最终放弃了,写下了我通常打算写的东西。

Edit2:......但我犯了一个错误。正确的方法是检查之前是否有空间阅读它。卫生署!

简单的测试程序:

int main (int argc, const char * argv[]) {
    char line0[100];
    int n0 = speek(line0, 4, stdin);

    fprintf(stderr, "%d '%s'\n", n0, line0);

    char line1[100];
    int n1 = speek(line1, 8, stdin);

    fprintf(stderr, "%d '%s'\n", n1, line1);

    return 0;
}

鉴于仅包含abcefghij的文件提供

3 'abc' 
7 'abcdefg'

答案 2 :(得分:0)

添加@Thiruvalluvar注意到的内容,

  1. 如果文件为空,peek只包含NULL个字符。 i = strlen(peek)将返回0,但您仍然进入循环,因为您有i>=0并尝试将某个角色推回到您从未从那里获得的流中。即使len为零,也会出现相同的情况!

  2. 您还没有监控ungetc的返回值。失败时可能会返回EOF

答案 3 :(得分:0)

除了检查NULLif (len > 0)的指针外,我建议您检查FILE *是否有效。您可以将其传递给fileno()并检查它是否返回与-1不同的值。