我正在为我的学校的课程提问。由于某些原因,我似乎无法使用scanf()
,我必须使用gets()
。
问题如下:
编写一个不再复制的C函数stringncpy()
比n个字符(跟随空字符的字符)
从s2
指向的数组到
s1
指向的数组。
如果s2
指向的数组是
一个短于n个字符的字符串,空字符
被附加到指向的数组中的副本
s1
,直到写完所有字符为止。
在
stringncpy()
返回s1
的值。
该功能 原型:
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;
}
有谁能告诉我这有什么问题? 谢谢。
答案 0 :(得分:1)
你不应该使用gets
;它被弃用了。 改为使用fgets
。
以下循环似乎违反了以下要求:
如果s2指向的数组是一个短于n个字符的字符串,则空字符将附加到s1指向的数组中的副本,直到写入所有n个字符。
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
,稍后length
分配给scanf
。
另一方面,如果您使用scanf("%s", ...)
,则"Hello"
将被sourceStr
读入,而"world\n" "13\n"
将被stdin
保留为"world\n"
。 .. 等待,如何将fgets
转换为十进制整数?这是否也可能导致不合逻辑的行为?
检查您的返回值!这对scanf
也很重要。由于您对int x = scanf("%s", sourceStr);
if (x != 1) { /* XXX: something went wrong! */ }
x = scanf("%d", &length);
if (x != 1) { /* XXX: something went wrong! */ }
的两次调用都需要一个字段,因此成功时它们都应返回1。 e.g。
scanf
如果您确实必须使用%[^\n]
来读取一行,则相应的转化规范为%s
,其中gets
与%39[^\n]
有类似问题(即,fgets
我不知道目标数组的大小,因此可能会导致溢出)。您应该在说明符前面加上一个长度,其中包括使用幻数(例如public class CalculatorController : Controller
{
public IActionResult Index(int id)
{
return Content($"Value: {id}");
}
}
)。最好使用最适合工作的工具,在本例中为routes.MapRoute(
name: "calculator",
template: "{controller=Home}/{action=Index}/{id?}");
。
答案 1 :(得分:0)
通过查看您的输入,
输入字符串: 这是一个测试 输入字符数: stringncpy():╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠this
很明显它没有给你输入数字的机会。 这意味着,如上面的答案所示,后面的字符 第一个空格留在stdin缓冲区中,它是自动的 分配给变量'length'。因此,您要查看分配给变量“length”的值。
在这种情况下,字符串被分配给一个int变量,我们得到了这个奇怪的结果。
以下是从用户提示中获取整数值的另一种方法:
printf("Enter the number of characters: \n");
fgets( sLength, 10, stdin );
length = atoi(sLength);
当你使用scanf()时,这种方法的问题是回车字符保留在STDIN缓冲区中。
答案 2 :(得分:-1)
的scanf(&#34;%S&#34;,sourceStr);不使用包含空格或换行符的字符串。 正如你已经给出了输入 &#34;这是一个文本。&#34;
你必须使用scanset 或获得功能
scanf("%[^\n]s",sourceStr);
这将读取整个字符串以及空格,直到遇到换行符。