【问题标题】:Input string consists of null terminating chars输入字符串由空终止字符组成
【发布时间】:2018-12-12 04:57:12
【问题描述】:

我正在使用 NanoPB 将编码数据(unsigned char 数组)从服务器发送到客户端。我将每个字节映射为单个char,将它们连接起来,然后通过网络作为一个完整的字符串发送。在客户端,我有一个串行接口,可以用getcgets 读取服务器的响应。问题是缓冲区可能有null-终止chars 和gets 会失败。例如,假设缓冲区包含如下内容:

unsigned char buffer[] = {72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 0, 24, 1, 32, 1, 40, 0};

为简单起见,我将缓冲区写入文件并尝试读回并重建它(在this 的帮助下):

#include <stdio.h>

void strInput(FILE *fp, char str[], int nchars) {
    int i = 0;
    int ch;
    while ((ch = fgetc(fp)) != '\n' && ch != EOF) {
        if (i < nchars) {
            str[i++] = ch;
        }
    }
    str[i] = '\0';
}

void readChars(FILE *fp)
{
    char c = fgetc(fp);
    while (c != EOF)
    {
        printf("%c", c);
        c = fgetc(fp);
    }
}


int main() {
    FILE *fp;
    const char* filepath = "mybuffer.txt";
    char c;
    char buffer[100];

    fp = fopen(filepath, "r+");    
    strInput(fp, buffer, sizeof(buffer));
    printf("Reading with strInput (WRONG): %s\r\n", buffer);
    fclose(fp);

    fp = fopen(filepath, "r+");
    printf("Reading char by char: ");
    readChars(fp);
    printf("\r\n");
    fclose(fp);

    getchar();
    return 0;
}

这是输出:

Reading with strInput (WRONG): Hello world
Reading char by char: Hello world  (

如何从该文件重建缓冲区? 为什么readChars 打印所有缓冲区但strInput 不打印?

【问题讨论】:

  • 您的问题是什么?请注意,1) gets() should never be used under any circumstances 和 2) gets()fgets() 都读取输入(包括空字节),直到找到换行符。
  • 不知道该告诉你什么。许多标准 C 函数假定 '\0' 是终止符。如果您的数据包含此字符,则需要避免使用这些函数,如果没有合适的函数,请编写自己的函数。
  • 如果缓冲区包含 NUL 终止符,则无法使用 printf 打印。你也不能用gets 阅读它。当然,无论如何你都应该never use gets。您应该使用fgetc 一次读取一个字节,或者使用fread 读取整个消息。
  • @MasoudR。是的,您可以使用getc 一次读取一个字节。但是您需要知道要读取多少字节。这可以通过先发送长度来完成。
  • "返回服务器响应(作为字符串) char by char" 这是不正确的。如果它不是以 NUL 结尾的,则它不是字符串。您没有字符串,因此不应将它们视为字符串。

标签: c nanopb


【解决方案1】:

“为什么readChars 打印所有缓冲区但strInput 不打印?”

readChars() 函数实际上在函数中打印所有读取的字符,一次一个:

while (c != EOF)
    {
        printf("%c", c);
        c = fgetc(fp);
    }

但是,strInput() 函数使用%s 转换说明符将buffer[] 的内容打印为字符串:

strInput(fp, buffer, sizeof(buffer));
printf("Reading with strInput (WRONG): %s\r\n", buffer);

这次遇到嵌入的\0 字符时,打印停止,因为%s 就是这样做的。

注意readChars() 函数中的c 应该是int,而不是charfgetc() 函数返回 int 值,EOF 可能无法在 char 中表示。

如果您想查看嵌入的空字节,请一次打印一个来自buffer[] 的字符:

#include <stdio.h>

int main(void)
{
    FILE *fp = fopen("mybuffer.txt", "r");  // should check for open failure

    char buffer[100] = { '\0' };  // zero to avoid UB when printing all chars
    fgets(buffer, sizeof buffer, fp);
//  could just as well use:
//  strInput(fp, buffer, sizeof(buffer));

    for (size_t i = 0; i < sizeof buffer; i++) {
        if (buffer[i] == '\0') {
            putchar('*');        // some character not expected in input
        }
        else {
            putchar(buffer[i]);
        }
    }
    putchar('\n');

    return 0;
}

【讨论】:

  • 谢谢,你的意思是 strInput 从文件中返回整个缓冲区?
  • 是的,直到换行。您也可以使用fgets(),但这将包括buffer[] 中的换行符(如果有空间的话)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多