2

我可以将int snprintf(char *str, size_t size, const char *format, ...); 特定数量的字符写入str.

如何从 c-string 中读取特定数量的字符?

问候

4

5 回答 5

6

您可以在格式参数中传递一个数字:

char buf[21];
sscanf(str, "%20s", buf);

这最多可将 20 个字符读入buf.

如果在编译时不知道要读取多少数据,可以在运行时准备格式字符串:

char format[20];
sprintf(format, "%%%ds", howMuchToRead);
sscanf(str, format, buf);
于 2012-07-18T10:53:18.567 回答
4

sscanf作为两者的替代strncpy方案,您还可以使用精度说明符(例如"%.20s"仅打印 20 个字符)。此 SO 帖子中讨论了C 字符串的精度说明符。这些步骤与解决方案中的基本相同,您创建一个格式字符串并使用它来捕获所需的字符。 在使用时,如果您使用提到的格式说明符 ie等,如果字符串包含空格,则不能保证您将获得 20 个字符;如果遇到空格,那么您只会在空格之前获得字符(因为空格是函数族的分隔符)。相反,您应该使用类似的东西sscanf
sscanf"%20s"scanf%20[^\n]. [^\n]表示读取直到换行,而 20 指定要扫描的字符数。所有这些都可以在以下示例中看到:

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

int main(void) {
        char format[20] = {0};
        char buf[50] = {0};
        char str[] = "Hello World! How are you?";
        size_t howMuchToRead = 8;

        /* Using sscanf - till whitespace or size specified */
        snprintf(format, sizeof format, "%%%zus", howMuchToRead);
        sscanf(str, format, buf);
        printf("Using sscanf with %%8s format :%s\n", buf);

        /* Using sscanf - read everything upto newline */
        snprintf(format, sizeof format, "%%%zu[^\n]", howMuchToRead);
        sscanf(str, format, buf);
        printf("Using sscanf with %%8[^\\n] format :%s\n", buf);

        /* Using precision specifier */
        snprintf(format, sizeof format, "%%.%zus", howMuchToRead);
        snprintf(buf, sizeof buf, format, str);
        printf("Using precision specifier :%s\n", buf);
        return 0;
}
/*
Output:
Using sscanf with %8s format :Hello
Using sscanf with %8[^\n] format :Hello Wo
Using precision specifier :Hello Wo
*/

sinelaw的回答提出了非常重要的几点,您应该小心。
希望这可以帮助!

于 2012-07-18T18:02:01.263 回答
2

sscanf,就像scanf函数一样,是有问题的。正如 GNU 手册页所说:

给定格式说明符必须有足够的地址参数;如果不是,结果是不可预测的,并且可能是灾难性的。

因此,您需要避免一个问题(编译器无法验证您是否传递了正确数量或类型的参数,尽管有些编译器有一个 hack 专门警告您这些函数)。这个问题的一部分还在于您需要在格式字符串中硬编码最大缓冲区大小(这使得使用整数常量来防止缓冲区溢出变得更加困难)。

由于您的用例只是从字符串中复制最多一定数量的字符,因此我将按照 Joachim Pileborg 的回答所建议的那样使用strncpy(并确保设置一个终止符)。'\0'对于长度参数,您应该使用输入和输出缓冲区的最小长度,减 1 以适应 terminating nul

换句话说(未经测试):

strncpy(dest, src, 
        MIN(NUM_OF_CHARS_TO_COPY, 
            MIN(DEST_BUFFER_SIZE, SRC_BUFFER_SIZE)) - 1);

其中MIN(a,b)相当于a < b ? a : bon 整数。

于 2012-07-18T14:07:00.517 回答
2

您可以使用strncpymemcpy。但是,请注意,strncpy在某些情况下可能不会附加终止'\0'字符,而且memcpy永远不会。此外,memcpy根本不检查字符串的结尾,它只是复制您要求它的字节数。

于 2012-07-18T10:53:39.530 回答
2

您可以使用sscanf

int sscanf(const char *str, const char *format, ...);

例如:

char out[4];
sscanf("foo", "%3s", &out);

当然,你也可以做一些更有趣的事情:

int value;
sscanf("value=10", "value=%d", &value);
于 2012-07-18T10:55:30.857 回答