我正在为我学校的一门类(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/