【问题标题】:Program Prints the string in the wrong way. strcpy程序以错误的方式打印字符串。字符串
【发布时间】:2020-08-24 06:19:17
【问题描述】:

在输入姓名和姓氏后(例如:姓名:Mario 姓氏:Rossi)作为输出而不是得到Mario Rossi,我得到ossi Rossi,但我不明白为什么。

int main() {
    char space[] = " ";
    char name[40], surname[40], space_name[40], space_surname[40];
    printf("what's your name");
    scanf("%[^\n]", &name);

    printf("Whats your surname");
    scanf(" %[^\n]", &surname);

    strcpy(space_surname, strcat(space, surname));
    strcat(name, space_surname);
    printf("%s", name);
}

【问题讨论】:

  • space 只能存储一个字符,但您要复制更多内容,从而覆盖任何内容。你看到的是未定义的行为,因为这个。
  • @usr2564301 谢谢你的回答,所以基本上解决这个问题的一个好方法是用空格[N]代替N一个大数字?你能告诉我其他解决这个问题的方法吗?
  • 是的,这将是处理它的标准方法。否则,您可以计算所需的所有空间并使用可变长度数组,或者您可以使用 malloc 动态分配空间。
  • 谢谢大家

标签: c c-strings strcpy strcat


【解决方案1】:

在您的代码中,您首先将space 末尾的surnamestrcat(space, surname) 连接起来,这具有未定义的行为,因为space 只有两个元素,一个空格和一个空终止符。在末尾复制surname 会破坏数组name,当name 变为ossi 时,您会观察到该数组。这种行为是未定义的,它在您的架构上以这种方式发生,但未定义的行为可能会产生其他后果,包括没有可见的影响或计算机崩溃。

还要注意这些备注:

  • 您应该告诉scanf() 要存储到namesurname 中的最大字符数,以避免在输入过长时出现未定义的行为。
  • 您应该传递 name 而不是 &name
  • 您应该测试scanf() 的返回值,以避免在无效输入上出现未定义的行为,例如在文件意外结束或第一个scanf() 出现空行的情况下。
  • 您可以定义具有始终定义行为的大小的数组。

为了更简洁的方法,您可以使用 2 个不同的数组 firstnamesurname 作为用户输入,并将名称构造为第三个数组 name,对于所有情况都足够大:

strcpy(name, firstname);
strcat(name, " ");
strcat(name, surname);

或可读性较差:

strcat(strcat(strcpy(name, firstname), " "), surname);

以上两种方法都会不必要地遍历已复制到name 中的字符。一个更清洁、更安全的解决方案是使用snprinf():

snprintf(name, sizeof name, "%s %s", firstname, surname);

这是修改后的版本:

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

int main() {
    char firstname[40]; /* up to 39 characters for the first name */
    char surname[40];   /* up to 39 characters for the last name */
    char name[80];      /* 39 chars + 1 space + 39 chars + 1 null terminator */

    printf("What is your name: ");
    if (scanf(" %39[^\n]", name) != 1)
        return 1;

    printf("What is your surname: ");
    if (scanf(" %39[^\n]", surname) != 1)
        return 1;

    /* simpler solution with `snprintf` */
    snprintf(name, sizeof name, "%s %s", firstname, surname);
    printf("%s\n", name);

    return 0;
}

【讨论】:

  • @ChristianGibbons:因此,我在main 末尾的替代更简单的解决方案
  • @ChristianGibbons:我重新调整了答案,但我避免了 efficiency 参数,因为对 strcat 的 2 次调用可能仍然比snprintf 开销。
【解决方案2】:

对于初学者来说,这些电话

scanf("%[^\n]", &name);

scanf(" %[^\n]", &surname);

无效。它们必须至少看起来像

scanf("%[^\n]", name);

scanf(" %[^\n]", surname);

数组space 没有足够的空间来追加存储在数组surname 中的字符串。所以这个电话

strcpy(space_surname, strcat(space, surname));

无效。

看来你的意思

strcat( strcpy( space_surname, space ), surname);

【讨论】:

    【解决方案3】:

    strcat(dest, src) 将连接srcdest。您的缓冲区space(长度为 1,不包括空终止符)不足以容纳两者。此外,您的 space_surname 将溢出,因为您将大小为 1 的字符串 (space) 大小为 40 的字符串 (surname) 存储到大小为 40 的缓冲区中。将其增加到至少 41 号。space 字符串也是不必要的,因为space 是字符,可以直接设置。

    space_surname[0] = ' ';
    space_surname[1] = '\0';  // So you know where to concat to
    strcat(space_surname, surname);
    

    请注意,您在使用 name 时遇到了同样的问题。您正在尝试将 name(长度 40)、space(长度 1)和 surname(长度 40)全部存储到 name 中。您需要创建一个大小为 81 或更大的新 full_name 变量并将其存储到该变量中。

    【讨论】:

      猜你喜欢
      • 2015-09-04
      • 1970-01-01
      • 2021-12-09
      • 2019-03-01
      • 2010-11-10
      • 2020-03-29
      • 2015-09-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多