运行scanf()的错误,tute使用gets()

时间:2017-04-08 05:13:29

标签: c arrays string

我正在为我的学校的课程提问。由于某些原因,我似乎无法使用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;
}

有谁能告诉我这有什么问题? 谢谢。

3 个答案:

答案 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);

这将读取整个字符串以及空格,直到遇到换行符。