简体   繁体   English

c语言中的scanf说明

[英]Scanf clarification in c language

Is it possible to read an entire string including blank spaces like gets() function in scanf() ?是否可以读取包含空格的整个字符串,例如scanf() gets()函数?

I am able to do it using the gets() function.我可以使用gets()函数来做到这一点。

char s[30];
gets(s);

This will read a line of characters.这将读取一行字符。 Can this be done in scanf() ?这可以在scanf()吗?

You can read a line, including blank spaces, with scanf() , but this function is subtle, and using it is very error-prone.您可以使用scanf()读取一行,包括空格,但是这个函数很微妙,使用它很容易出错。 Using the %[^\\n] conversion specifier, you can tell scanf() to match characters to form a string, excluding '\\n' characters.使用%[^\\n]转换说明符,您可以告诉scanf()匹配字符以形成字符串,不包括'\\n'字符。 If you do this, you should specify a maximum field width.如果这样做,则应指定最大字段宽度。 This width specifies the maximum number of characters to match, so you must leave room for the '\\0' terminator.此宽度指定要匹配的最大字符数,因此您必须为'\\0'终止符留出空间。

It is possible that the first character in the input stream is a '\\n' .输入流中的第一个字符可能是'\\n' In this case, scanf() would return a value of 0 , since there were no matches before encountering the newline.在这种情况下, scanf()将返回值0 ,因为在遇到换行符之前没有匹配项。 But, nothing would be stored in s , so you may have undefined behavior.但是, s不会存储任何内容,因此您可能有未定义的行为。 To avoid this, you can call scanf() first using the %*[\\n] conversion specifier, discarding any leading '\\n' characters.为避免这种情况,您可以首先使用%*[\\n]转换说明符调用scanf() ,丢弃任何前导'\\n'字符。

After the string has been read, there will be additional characters in the input stream.字符串被读取后,输入流中会有额外的字符。 At least a '\\n' is present, and possibly more characters if the user entered more than the maximum field width specifies.至少存在一个'\\n' ,如果用户输入的字符超过指定的最大字段宽度,则可能还有更多字符。 You might then want to discard these extra characters so that they don't interfere with further inputs.然后您可能想要丢弃这些额外的字符,以便它们不会干扰进一步的输入。 The code below includes a loop to do this operation.下面的代码包含一个循环来执行此操作。

The first call to scanf() will consume all newline characters in the input stream until a non-newline character is encountered.第一次调用scanf()将消耗输入流中的所有换行符,直到遇到非换行符。 While I believe that the second call to scanf() should always be successful, it is good practice to always check the return value of scanf() (which is the number of successful assignments made).虽然我认为对scanf()的第二次调用应该总是成功的,但始终检查scanf()的返回值(这是成功分配的次数scanf()是一种很好的做法。 I have stored this value in result , and check it before printing the string.我已将此值存储在result ,并在打印字符串之前检查它。 If scanf() returns an unexpected result, an error message is printed.如果scanf()返回意外结果,则会打印错误消息。

It is better, and easier, to use fgets() to read entire lines.使用fgets()读取整行会更好也更容易。 You must remember that fgets() keeps the trailing newline, so you may want to remove it.您必须记住fgets()保留了尾随换行符,因此您可能希望将其删除。 There is also a possibility that the user will enter more characters than the buffer will store, leaving the remaining characters in the input stream.也有可能用户输入的字符多于缓冲区存储的字符数,而将剩余的字符留在输入流中。 You may want to remove these extra characters before prompting for more input.在提示更多输入之前,您可能希望删除这些额外的字符。

Again, you should check the return value of fgets() ;同样,您应该检查fgets()的返回值; this function returns a pointer to the first element of the storage buffer, or a NULL pointer in the event of an error.此函数返回指向存储缓冲区第一个元素的指针,或在发生错误时返回NULL指针。 The code below replaces any trailing newline character in the string, discards extra characters from the input stream, and prints the string only if the call to fgets() was successful.下面的代码替换字符串中的任何尾随换行符,丢弃输入流中的额外字符,并仅在调用fgets()成功时才打印字符串。 Otherwise, an error message is printed.否则,将打印错误消息。

#include <stdio.h>

int main(void)
{
    char s[30];
    int result;

    printf("Please enter a line of input:\n");
    scanf("%*[\n]");                // throw away leading '\n' if present
    result = scanf("%29[^\n]", s);  // match up to 29 characters, excluding '\n'

    /* Clear extra characters from input stream */
    int c;
    while ((c = getchar()) != '\n' && c != EOF)
        continue;                   // discard extra characters

    if (result == 1) {
        puts(s);
    } else {
        fprintf(stderr, "EOF reached or error in scanf()\n");
    }

    printf("Please enter a line of input:\n");    
    char *ps = fgets(s, 30, stdin); // keeps '\n' character

    if (ps) {
        while (*ps && *ps != '\n') {
            ++ps;
        }
        if (*ps) {                  // replace '\n' with '\0'
            *ps = '\0';
        } else {
            while ((c = getchar()) != '\n' && c != EOF)
                continue;           // discard extra characters
        }

        puts(s);

    } else {
        fprintf(stderr, "EOF reached or error in fgets()\n");
    }

    return 0;
}

Note that these two methods of getting a line of input are not exactly equivalent.请注意,这两种获取输入行的方法并不完全等效。 The scanf() method, as written here, does not accept an empty line (ie, a line consisting of only the '\\n' character), but does accept lines consisting of other whitespace characters.此处所写的scanf()方法不接受空行(即仅由'\\n'字符组成的行),但接受由其他空白字符组成的行。 The fscanf() method will accept an empty line as input. fscanf()方法将接受一个空行作为输入。

Also, if it is acceptable to ignore leading whitespace characters, it would be simpler to follow the recommendation given by Jonathan Leffler in the comments to use only a single call to scanf() :此外,如果忽略前导空格字符是可以接受的,那么遵循 Jonathan Leffler 在评论中给出的建议只使用一次scanf()调用会更简单:

result = scanf(" %29[^\n]", s);

This will ignore leading whitespace characters, including newlines.这将忽略前导空白字符,包括换行符。

Do not use scanf() or gets() function — use fgets() instead.不要使用scanf()gets()函数 — 使用fgets()代替。 But for the above question please find the answer.但是对于上面的问题,请找到答案。

int main() {
    char a[30];
    scanf ("%29[^\n]%*c", name);
    printf("%s\n", a);
    return 0;
}

Its also highly recommended like I told in the beginning to use fgets() instead.它也强烈推荐,就像我在开始时所说的那样使用fgets()代替。 We clearly do not understand the weird requirement.我们显然不理解奇怪的要求。 I would have used the fgets() to read the character.我会使用fgets()来读取字符。

fgets(a, size(a), stdin);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM