【问题标题】:Why can't I just use this array without specifying its size?为什么我不能只使用这个数组而不指定它的大小?
【发布时间】:2022-01-20 14:05:44
【问题描述】:
int main()
{
    struct Student_struct {
        char name[40];
        int age;
        float grade;
    };

    struct Student_struct student;

    printf("---------------------Student-----------------------\n\n\n");
    student.name[] = "person";
    student.age = 20;
    student.grade = 7.5;
    
    return 0;
}

我收到以下错误:']'之前的预期表达式

我知道我可以使用 strcpy(student.name, "person") 或 student.name[6] = "person",但为什么不能将其编码为 student.name[] = "person"?这背后的逻辑是什么?

【问题讨论】:

  • 请编辑您的帖子以添加代码格式和缩进。
  • student.name[] = "person" ==> strcpy(student.name, "person"); 别忘了#include <string.h>
  • student.name[6] = "person" 不会做你想做的事,student.name[] = "person" 只是语法不正确。
  • 因为name[] 没有任何意义。 name 已经是一个数组了,[] 添加了什么?
  • 还要注意char name[6] = "person" 是一个错误。您需要至少 7 个字符来保存字符串。

标签: arrays c variables struct char


【解决方案1】:

数组大小已在结构声明中定义。在声明后使用方括号将访问数组中的元素,因此会出错。

【讨论】:

    【解决方案2】:

    在 C 中,您不能在运行时分配整个数组,它没有合理的理由,语言就是这样设计的。您只能在初始化期间设置数组中的所有项目。同样,您不能从函数返回数组。

    在这种情况下,简单的解决方法是strcpy(student.name, "person");

    然而,虽然您不能在运行时分配整个数组,但您可以分配整个结构。这是一种可能的解决方法——通过创建一个临时的 compound literal 结构,我们可以这样做:

    student = (struct Student_struct){ .name = "person", .age=20, .grade=7.5 };
    

    【讨论】:

      【解决方案3】:

      我知道我可以使用 strcpy(student.name, "person") 或 student.name[6] = "person"

      很好,但是你知道后者不会做你期望的吗?

      数组不是 C 中的一等公民。句号。不能仅仅因为 C 语言不允许,就将数组作为赋值的左成员。

      因此,当您使用 student.name[6] 时,这不是 6 个字符的数组,而只是第 7 个th 字符。语言允许这样做,因为字符是数字类型,并且指针可以转换为 int。

      所以student.name[6] = "person" 首先获取一个指向 litteral 字符串的第一个元素的指针 "person" 将其转换 (*) 为一个整数值(如果指针大于整数,则可能已经定义了实现),然后尝试存储如果char 不是无符号的,则将其转换为单个字符,该字符会调用未定义的行为。 你真的知道吗?


      (*) 实际上更糟糕的是,该语言需要显式强制转换才能将指针转换为算术值,因此该代码至少应该引发警告并且警告不能被忽略 .因此,由于它违反了约束,因此代码不是有效的 C。不过,如果被要求将此警告视为错误,我所知道的所有常见实现都将停止,否则将继续我上面描述的方式。

      【讨论】:

      • "将其转换为整数值" 不,您所说的转换仅在代码有效 C 时才会发生。student.name[6] = "person" 是违反 6.5.16.1 的约束,因此编译器必须生成诊断信息。并且不知道编译器生成的任何二进制文件从那里开始会做什么。
      • 具体请参见 6.5.4 约束“涉及指针的转换,除了 6.5.16.1 的约束允许的情况外,应通过显式强制转换来指定。”
      • @Lundin 那么student.name[6] = "person" 是否可以归结为将char * 直接转换为char(无需通过int 作为上述答案),然后适用6.3.1.3? (char 签名时的潜在 UB,否则截断)
      • @chux-ReinstateMonica 由于代码无效,没有进行转换。唯一允许的指针隐式转换是下面列出的 6.5.16.1 简单赋值。这包括与 void 指针和空指针的转换。
      • 更多信息在这里(我刚刚用 6.5.4 的这个非常清晰的引用更新了它):"Pointer from integer/integer from pointer without a cast" issues
      【解决方案4】:

      尺寸不足不是问题。指定大小没有帮助。

      问题是您试图分配给一个数组。这是不允许的。您需要使用strcpy 等。

      strcpy(student.name, "person");
      

      在这种特殊情况下,您可以初始化数组而不是分配给它。

      struct Student_struct student = {
         .name  = "person",
         .age   = 20,
         .grade = 7.5
      };
      

      【讨论】:

      • 不,strncpy 绝不能用于任何目的。请不要教给初学者。见Is strcpy dangerous and what should be used instead?
      • @Lundin,真的,我不会使用它,因为你最终得到一个不完整的字符串。 (我不确定这页是否是这样说的;我看了看,但我没有看到它在两页密集的页面后给出的原因!!!)已修复。当我在那里时,我在我的答案中添加了一种适用于这种情况的替代方法。
      • 向下滚动到“strncpy 怎么样?”。它给出了令人讨厌的不正确谣言的背景,即 strncpystrcpy 的安全版本,strncpy 的实际目的是什么以及为什么在任何 C 程序中都不允许它太危险。
      • @ryyker 没关系。如果它设置为全零并且您将数组大小传递给strncpy,它将用数据覆盖每个零,而不是空终止字符串。该函数被设计破坏了,或者更确切地说,它从不打算用于以空字符结尾的字符串。
      • 不知道为什么它被删除,但我留下了一条评论,可以使用strncpy(dst, src, sz-1); dst[sz-1] = 0; 解决缺少 NUL 终止的问题。但是你仍然留下一个不完整的字符串。
      【解决方案5】:

      它不起作用仅仅是因为它是无效的语法。如果要进行初始化,可以执行以下操作:

      #include <stdio.h>
      
      int
      main(void)
      {
              struct student {
                      char name[40];
                      int age;
                      float grade;
              };
      
              struct student student = {
                      "person",
                      20,
                      7.5
              };
      
              struct student student2 = {
                      .name = "person",
                      .age = 20,
                      .grade = 7.5
              };
      
              printf("---------------------Student-----------------------\n\n\n");
              printf("%s\n", student.name);
      
              return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 2019-04-28
        • 2011-09-17
        • 1970-01-01
        • 2011-04-22
        • 2020-07-30
        • 2015-02-25
        • 1970-01-01
        • 1970-01-01
        • 2021-10-14
        相关资源
        最近更新 更多