4

Here's what the Beez C guide (LINK) tells about the %[] format specifier:

It allows you to specify a set of characters to be stored away (likely in an array of chars). Conversion stops when a character that is not in the set is matched.

I would appreciate if you can clarify some basic questions that arise from this premise:

1) Are the input fetched by those two format specifiers stored in the arguments(of type char*) as a character array or a character array with a \0 terminating character (string)? If not a string, how to make it store as a string , in cases like the program below where we want to fetch a sequence of characters as a string and stop when a particular character (in the negated character set) is encountered?

2) My program seems to suggest that processing stops for the %[^|] specifier when the negated character | is encountered.But when it starts again for the next format specifier,does it start from the negated character where it had stopped earlier?In my program I intend to ignore the | hence I used %*c.But I tested and found that if I use %c and an additional argument of type char,then the character | is indeed stored in that argument.

3) And lastly but crucially for me,what is the difference between passing a character array for a %s format specifier in printf() and a string(NULL terminated character array)?In my other program titled character array vs string,I've passed a character array(not NULL terminated) for a %s format specifier in printf() and it gets printed just as a string would.What is the difference?

//Program to illustrate %[^] specifier

#include<stdio.h>

int main()
{
char *ptr="fruit|apple|lemon",type[10],fruit1[10],fruit2[10];

sscanf(ptr, "%[^|]%*c%[^|]%*c%s", type,fruit1, fruit2);
printf("%s,%s,%s",type,fruit1,fruit2);
}

//character array vs string

#include<stdio.h>

int main()
{
char test[10]={'J','O','N'};
printf("%s",test);
}

Output JON

//Using %c instead of %*c

#include<stdio.h>

int main()
{
char *ptr="fruit|apple|lemon",type[10],fruit1[10],fruit2[10],char_var;

sscanf(ptr, "%[^|]%c%[^|]%*c%s", type,&char_var,fruit1, fruit2);
printf("%s,%s,%s,and the character is %c",type,fruit1,fruit2,char_var);

}

Output fruit,apple,lemon,and the character is |

4

2 回答 2

6
  1. 它是空终止的。从sscanf()

    除了匹配的字符之外,转换说明符 s 和 [ 始终存储空终止符。目标数组的大小必须至少比指定的字段宽度大一。

  2. 排除的字符不被扫描集消耗,并且仍有待处理。另一种格式说明符:

    if (sscanf(ptr, "%9[^|]|%9[^|]|%9s", type,fruit1, fruit2) == 3)
    
  3. 该数组实际上是空终止的,因为剩余的元素将被初始化为零:

    char test[10]={'J','O','N' /*,0,0,0,0,0,0,0*/ };
    

如果它不是空终止的,那么它将继续打印,直到在内存中的某处找到空字符,可能会超出数组的末尾,从而导致未定义的行为。可以打印非空终止数组:

    char buf[] = { 'a', 'b', 'c' };
    printf("%.*s", 3, buf);
于 2013-05-09T04:52:34.837 回答
1

1) 这两个格式说明符获取的输入是作为字符数组还是以 \0 终止字符(字符串)存储在参数(char* 类型)中的?如果不是字符串,如何将其存储为字符串,在下面的程序中,我们想要获取一系列字符作为字符串并在遇到特定字符(在否定字符集中)时停止?

它们以 ASCIIZ 格式存储 - 带有 NUL/'\0' 终止符。

2) 我的程序似乎建议当否定字符 | 时停止处理 %[^|] 说明符 遇到了。但是当它为下一个格式说明符再次启动时,它是否从之前停止的否定字符开始?在我的程序中,我打算忽略 | 因此我使用了 %*c。但是我测试并发现如果我使用 %c 和一个 char 类型的附加参数,那么字符 | 确实存储在该参数中。

它不应该消耗下一个字符。向我们展示您的代码,否则它不会发生;-P。

3) 最后但对我来说至关重要的是,在 printf() 中为 %s 格式说明符传递字符数组和字符串(NULL 终止字符数组)之间有什么区别?在我的另一个标题为字符数组与字符串的程序中,我已经为 printf() 中的 %s 格式说明符传递了一个字符数组(不是以 NULL 结尾),它就像字符串一样被打印出来。有什么区别?

(编辑:以下解决了上面的问题,它一般谈论数组行为,并且比专门提出案例char[10] = "abcd";并且安全的问题中的代码片段更广泛)

%s必须传递一个指向 ASCIIZ 文本的指针...即使该文本显式在 char 数组中,它也是定义文本内容而不是数组长度的 NUL 终止符的强制存在。您必须 NUL 终止您的字符数组,否则您有未定义的行为。有时您可能会侥幸逃脱 - 例如 strncpy 到数组中将 NUL 终止它,如果且仅当有空间这样做时,静态数组以全 0 内容开始,所以如果您只在最后一个字符之前覆盖你'将有一个 NUL,您的 char[10] 示例恰好有未指定值的元素填充了 NUL,但您通常应该负责确保某些东西确保 NUL 终止。

于 2013-05-09T04:55:35.850 回答