繁体   English   中英

全线输入的极端麻烦。 C编程语言

[英]Extreme troubles with full line input. C Programming Language

我有一个绝对最疯狂的时间来获得全线输入。 我会解释我的问题。 我需要从键盘输入的用户那里获得一整行输入, 包括空格。 简单吧? 错误!

我的目标

将带有空格的多个字符串存储到变量中。 如果它有所不同,我想使变量等于char指针。 所以一旦我从tempString获得输入,我想将它设置为char指针。 像这样:

char *variable1, *variable2;
//get user input
variable1 = tempString;
//get more user input
variable 2 = tempString;
//etc etc etc

这是我尝试过的。

第一次尝试

char tempString[100];
scanf("%s", &tempString);
printf("%s", tempString);

无效: scanf将停止在空白区域读取,因此“ Example String ”最终将成为“ Example ”。

第二次尝试

所以我做了更多的研究。 我以为我找到了神奇的修复。

char tempSTring[100];
fgets(tempString, 100, stdin);
printf("%s", tempString);

最初这是有效的。 然而,存在一个大问题。 我需要让用户输入大约8个输入。 意思是我必须使用这样的命令8次。 问题是程序经常跳过fgets命令。 如果我以前使用scanf ,不知何故\\n字符卡在输入流中,并自动输入fgets ,满足其stdin input ,然后不提示用户输入。

第三次尝试

在考虑fgets可能是我的解决方案之后,我尝试了一些技巧。

char tempSTring[100];
getc(stdin);
fgets(tempString, 100, stdin);
printf("%s", tempString);

我尝试添加这个getc(stdin)行。 它适用于我的大部分计划。 它吸收了流中留下的\\n字符。 当它这样做,很棒,它的工作原理。 但有时,出于某种原因, \\n不会留在流中,并且在调试时,看起来getc(stdin)正在请求来自用户的输入,因此它会暂停我的程序以请求输入。

这些对我不起作用。

  • 我该怎么做这个简单的任务?

要从文件中读取(最多)8行,您可以使用这些解决方案中的任何一种。 我拒绝使用变量char *variable1, *variable2, …; - 这是一个寻求逃避的阵列。

POSIX getline()

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    enum { MAX_LINES = 8 };
    char *lines[MAX_LINES];
    int   index = 0;
    char *buffer = 0;
    size_t buflen = 0;

    while (index < MAX_LINES && getline(&buffer, &buflen, stdin) != -1)
    {
        lines[index++] = buffer;
        buffer = 0;
        buflen = 0;
    }
    free(buffer);  // Space may be allocated before EOF is detected

    for (int i = 0; i < index; i++)
        printf("%d: %s", i, lines[i]);

    return 0;
}

如果getline()无法分配内存,它将报告错误,因此无需进行显式错误检查。

标准C fgets()

代码使用strdup() ,另一个POSIX函数。 它不是标准C的一部分(虽然它可以广泛使用)。 实施起来很简单。

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

int main(void)
{
    enum { MAX_LINES = 8 };
    char *lines[MAX_LINES];
    int   index = 0;
    char   buffer[4096];

    while (index < MAX_LINES && fgets(buffer, sizeof(buffer), stdin) != 0)
    {
        if ((lines[index] = strdup(buffer)) == 0)
            break;
        index++;
    }

    for (int i = 0; i < index; i++)
        printf("%d: %s", i, lines[i]);

    return 0;
}

循环中的测试允许strdup()无法分配内存的可能性。

笔记

上述两种解决方案都将换行符保留在输入字符串的末尾。 如果你不想那样,你可以用它来消除它:

lines[i][strcspn(lines[i], "\r\n")] = '\0';

这将使用空字节覆盖回车符或换行符,从而转换DOS或Unix行结尾。 然后,您需要调整打印,假设字符串包含换行符。 请注意,即使字符串中没有回车符或换行符,显示的表达式也能正常工作。

fgets()解决方案将断行4095个字符,其余部分将被读作“下一行”。 如果这是不可接受的,您可以采取各种策略。

  1. 您可以检测是否存在换行符并安排分配更多内存并将该行的下一部分读入额外内存,重复直到遇到换行符或EOF。
  2. 您可以读取换行符或EOF之前的剩余字符:

     int c; while ((c = getchar()) != EOF && c != '\\n') ; 

实现strdup()

如果由于某种原因你的系统没有strdup()的实现,你可以创建一个代理:

#include <assert.h>
#include <stdlib.h>
#include <string.h>

char *strdup(const char *old_str)
{
    assert(old_str != 0);
    size_t old_len = strlen(old_str) + 1;
    char *new_str = malloc(old_len);
    if (new_str != 0)
        memmove(new_str, old_str, old_len);
    return new_str;
}

这是我们老屁C程序员会怎么做的:

#include <stdio.h>

#define MAX_LEN 100

int main( )
{
    int c;
    char input[MAX_LEN+1];
    int i = 0;

    while ( (c=getchar()) != '\n' && c != EOF && i < MAX_LEN)
        input[i++] = c;
    if (c == EOF || c =='\n') {
        /* received input that terminated within buffer limit */
        input[i] = '\0';
        printf("read in your input string of: %s\n", input);
    }
    else {
        printf("don't buffer overflow me dude!\n");
        return -1;
    }
    return 0;    
}

但是现在人们会告诉你使用其中一个库函数。 我现在还是个老屁。

编辑 :修正了下面有用的评论指出的令人尴尬的错误。

您可以通过以下方式编写前一个scanf来保留'\\n' -

scanf("%d%*c", &x);     //<-- example to take int input

%*c将从stdin读取然后丢弃它,因此'\\n'将从stdin删除。

您可以像这样使用scanf一种前一次尝试的方式 ) -

char tempString[100];
/* As suggested by chqrile it is essential to check return of scanf */
if(scanf("%99[^\n]", tempString)!=1){   
                //  ^^ & not required
     tempString[0]='\0';
}

%99[^\\n]这将读取99字符,并且只有在遇到'\\n'后才会停止,因此会读取带空格的输入。

暂无
暂无

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

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