c - 运行 scanf() 时出错,tute 使用 gets()

标签 c arrays string

我正在为我学校的一门类(class)解答一个问题。由于某种原因,我似乎无法使用 scanf(),而我必须使用 gets()

问题如下:

编写一个不复制更多内容的 C 函数 stringncpy() 多于 n 个字符(空字符后面的字符 没有被复制)从s2指向的数组到 s1 指向的数组。

如果s2指向的数组是 短于 n 个字符的字符串,空字符 附加到指向的数组中的副本 s1,直到n个字符全部写入完毕。

stringncpy() 返回 s1 的值。

函数 原型(prototype):

char *stringncpy(char * s1, char * s2, int n);

此外,编写一个C程序来测试stringncpy 功能。你的程序应该读取字符串和 定位用户的 n 个字符,然后调用 功能与用户输入。

在此计划中,您是 不允许使用 C 标准中的任何函数 字符串库

当我成功构建后运行程序时,我不断收到以下错误。

Enter the string:
this is atest
Enter the number of characters:
stringncpy(): ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠this

实现代码如下:

#include <stdio.h> 
char *stringncpy(char *s1, char *s2, int n);
int main()
{
    char sourceStr[40], targetStr[40], *target;
    int length;
    printf("Enter the string: \n");
    //scanf("%s",sourceStr); //doesn't work for some reason
    gets(sourceStr); 
    printf("Enter the number of characters: \n");
    scanf("%d", &length);
    target = stringncpy(targetStr, sourceStr, length);
    printf("stringncpy(): %s\n", target);
    return 0;
}
char *stringncpy(char *s1, char *s2, int n)
{
    /* Copy source to target */
    int i, j;
    for (i = 0; i < n; i++)
    {
        if (s2[i] == '\0')
        {
            break;
        }
        else
        {
            s1[i] = s2[i];
        }
    }
    //s1[i + 1] = '\0';
    for (j = i + 1; j <= n; j++)
    {
        s1[j] = '\0';
    }
    return s1;
}

谁能告诉我这是怎么回事? 谢谢。

最佳答案

你不应该使用gets;它已被弃用。 改用fgets

以下循环似乎违反了以下要求:

If the array pointed to by s2 is a string shorter than n characters, null characters are appended to the copy in the array pointed to by s1, until n characters in all have been written.

for (j = i + 1; j <= n; j++)
{
    s1[j] = '\0';
}

这导致 n+1 个字符被写入。这是否可能导致差一(缓冲区溢出),这是未定义的行为,并且可能导致不合逻辑的行为?

还需要注意的是,scanf 返回一个值,如果您要验证该值,您就会尽早发现错误!

该错误是,scanf("%s", ...)gets(...) 不同。 gets 读取一行输入,而将 scanf("%s", ...) 视为读取内容更合适输入的单词(空格分隔的标记)。

逻辑如下:如果您的输入是 "Hello world\n" 后跟 "13\n"gets 将读取 "Hello world\n"sourceStr 中,然后 "13\n" 将保留在 stdin 中以分配给稍后通过 scanf 进行 length

另一方面,如果您使用 scanf("%s", ...) 那么 "Hello" 将被读入 sourceStr"world\n""13\n" 将留在 stdin 中... 等等,你如何转换 “world\n” 为十进制整数?这也可能导致不合逻辑的行为吗?

检查您的返回值!这对于 fgets 也很重要。由于对 scanf 的两次调用都需要一个字段,因此成功时它们都应返回 1。例如

int x = scanf("%s", sourceStr);
if (x != 1) { /* XXX: something went wrong! */ }

x = scanf("%d", &length);
if (x != 1) { /* XXX: something went wrong! */ }

如果您确实必须使用 scanf 来读取一行,则适当的转换规范将是 %[^\n],类似于 %s 与 gets 具有类似的问题(即它不知道目标数组的大小,因此可能会导致溢出)。您应该在说明符前加上长度前缀,这涉及使用魔数(Magic Number)(例如在您的情况下 %39[^\n] )。最好使用最适合这项工作的工具,在本例中是fgets

关于c - 运行 scanf() 时出错,tute 使用 gets(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43290433/

相关文章:

c - 生成数组中的随机数并计算平均值、最大值、最小值、总和

c - 使用数组表示法访问函数内的三重指针

c - 我正在做一个混合 2 个单词的(字符串)函数,但程序根本不工作

c - 是否有任何操作系统为 malloc() 实现缓冲?

c - IO重定向和缓冲区问题,fflush和c

将数组转换为 int/float

java - 在数组中按姓氏搜索

c# - 如何从字符串中删除空格?

java - 通过java中的管道流丢失数据

c - 保护或加密来自 C 程序的输入/输出?