Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
fgetc返回一个奇怪的字符_C_Char - Fatal编程技术网

fgetc返回一个奇怪的字符

fgetc返回一个奇怪的字符,c,char,C,Char,我使用fgetc()读取输入直到EOF。我遇到了一个奇怪的问题。就在EOF之前,我得到了一个char\337。我不知道那是什么 以下是我的代码实现: char *get_file_paths() { char *return_str = NULL; int chars_read = 0; size_t buf_sz = 80; return_str = (char *) malloc(buf_sz * sizeof(char))

我使用
fgetc()
读取输入直到EOF。我遇到了一个奇怪的问题。就在EOF之前,我得到了一个char
\337
。我不知道那是什么

以下是我的代码实现:

char *get_file_paths() 
{
        char *return_str = NULL;
        int chars_read = 0;
        size_t buf_sz = 80;

        return_str = (char *) malloc(buf_sz * sizeof(char));

        while((*(return_str + chars_read) = fgetc(stdin)) != EOF) {
                chars_read++;
                if ((chars_read + 1) == buf_sz) {
                        buf_sz *= 2;
                        return_str = realloc(return_str, buf_sz);
                }
        }

        return return_str;

}
例如,如果我有一个字符串:
assignment\u 2/grepout.txt
。在gdb中查看
return\u str
时,我得到以下信息:

assignment_2/grepout.txt\n\337
我真的很好奇这是什么意思。我在网上看了看,但没有提到。它可能是特定于平台的吗

我正在运行以下版本的gcc:

gcc version 4.8.1 20130909 [gcc-4_8-branch revision 202388] (SUSE Linux)

我正在运行openSuse。

您没有标记字符串的结尾

return_str[chars_read] = '\0';
return return_str;

你没有标记绳子的末端

return_str[chars_read] = '\0';
return return_str;

重要的是不要键入强制将
fgetc()
返回到
char
fgetc()
(和fgets())返回
int
,而不是
char
,原因正是EOF是一个超出字符范围的值。在大多数实现中,0337(0xFF或255十进制)是有效字符(在代码页1252、ISO-8859-15和Unicode中是字符ÿ)。 在循环中,如果在键盘上输入该字符,将具有与EOF相同的行为

因此,应将循环更改为:

char *get_file_paths(void) 
{  
    int chars_read = 0;
    size_t buf_sz = 0;
    int ch;
    char *return_str = NULL;

    while((ch = fgetc(stdin)) != EOF) {
        if(chars_read == buf_sz) {
            buf_sz += 80;
            void *no_leak = realloc(return_str, buf_sz+1);
            if(!no_leak) {
              perror("No memory\n");
              abort();
            }
            return_str = no_leak;
         }
         return_string[chars_read++] = ch;
    }
    if(return_string)
        return_string[chars_read++] = 0;
    return return_str;
}
我改变了其他几个小“问题”

  • 第一个参数为
    NULL的
    realloc()
    malloc()
    相同,因此通过在循环中重新安排(重新)分配,可以避免不必要的代码
  • sizeof(char)
    定义为1,无需说明
  • EOF值(即-1)不会进入循环,也不会与字符0xFF混淆
  • 如果已达到EOF,则函数返回NULL。这是一个功能性的选择,可能有帮助(也可能没有)。这取决于上下文
  • 使用数组语法(
    a[x]
    而不是
    *(a+x)
    ),它的可读性要高得多

编辑:添加分配检查。使用了一种严厉的方法。在这种情况下,我们还能做些什么?

重要的是不要键入强制将
fgetc()
返回到
char
fgetc()
(和fgets())返回
int
,而不是
char
,原因正是EOF是一个超出字符范围的值。在大多数实现中,0337(0xFF或255十进制)是有效字符(在代码页1252、ISO-8859-15和Unicode中是字符ÿ)。 在循环中,如果在键盘上输入该字符,将具有与EOF相同的行为

因此,应将循环更改为:

char *get_file_paths(void) 
{  
    int chars_read = 0;
    size_t buf_sz = 0;
    int ch;
    char *return_str = NULL;

    while((ch = fgetc(stdin)) != EOF) {
        if(chars_read == buf_sz) {
            buf_sz += 80;
            void *no_leak = realloc(return_str, buf_sz+1);
            if(!no_leak) {
              perror("No memory\n");
              abort();
            }
            return_str = no_leak;
         }
         return_string[chars_read++] = ch;
    }
    if(return_string)
        return_string[chars_read++] = 0;
    return return_str;
}
我改变了其他几个小“问题”

  • 第一个参数为
    NULL的
    realloc()
    malloc()
    相同,因此通过在循环中重新安排(重新)分配,可以避免不必要的代码
  • sizeof(char)
    定义为1,无需说明
  • EOF值(即-1)不会进入循环,也不会与字符0xFF混淆
  • 如果已达到EOF,则函数返回NULL。这是一个功能性的选择,可能有帮助(也可能没有)。这取决于上下文
  • 使用数组语法(
    a[x]
    而不是
    *(a+x)
    ),它的可读性要高得多


编辑:添加分配检查。使用了一种严厉的方法。在这种情况下,我们还能做什么?

字符\377是EOF。只需在从函数返回之前添加
*(return_str+chars_read)=0
:它将用字符串零的mandadory结尾覆盖EOF字符。奇怪的是,EOF是如何添加的?此行:
*(return_str+chars_read)=fgetc(stdin)!=EOF
不会阻止添加EOF,因为它是fgetc返回的值。如果文件有80多个字符,如果(字符读取>=缓冲区大小)中断,则应在循环
中进行检查
@JoëlHecht:更准确地说,
'\377'
是将
EOF
的值转换为type
char
(假设
char\u位==8
)的结果。
EOF
的值(通常)为
-1
。char\377为EOF。只需在从函数返回之前添加
*(return_str+chars_read)=0
:它将用字符串零的mandadory结尾覆盖EOF字符。奇怪的是,EOF是如何添加的?此行:
*(return_str+chars_read)=fgetc(stdin)!=EOF
不会阻止添加EOF,因为它是fgetc返回的值。如果文件有80多个字符,如果(字符读取>=缓冲区大小)中断,则应在循环
中进行检查
@JoëlHecht:更准确地说,
'\377'
是将
EOF
的值转换为type
char
(假设
char\u位==8
)的结果。
EOF
的值(通常)
-1
。当程序输入正好为80个字符时会发生什么?在OP的代码示例中,当读取第79个字符时,缓冲区大小会加倍。因此不可能写入未分配的内存。如果在键盘中键入ÿ会发生什么?当程序输入正好为80个字符时会发生什么?在OP的代码示例中,当读取第79个字符时,缓冲区大小会加倍。所以不可能写入未分配的内存。如果在键盘上键入ÿ会发生什么?你可能是指如果(chars_read>=buf_sz-1)
,你需要一个初始的
malloc
是的。更改了分配以处理它(仍然不需要malloc())。在将其存储到缓冲区指针之前,我们应该检查
realloc
的返回值是否为
null
。如果发生任何错误,我们将停止丢失缓冲区地址。我们应该将返回值存储在一个临时变量中,并检查
null
。您的意思可能是
if(chars_read>=buf_sz-1)
,您确实需要一个初始
malloc
是。更改了分配以处理它(仍然不需要