【问题标题】:Whats the difference between "abc" and {"abc"} in C?C中的“abc”和{“abc”}有什么区别?
【发布时间】:2009-09-02 23:47:17
【问题描述】:

特别是在 C 中(我想这也适用于 C++),两者有什么区别

char str[4] = "abc";
char *cstr = {"abc"};

当我尝试将“abc”传递给接受 char** 的函数时出现问题

void f(char** s)
{
  fprintf(stderr, "%s", *s);
}

执行以下操作会产生编译器错误。如果转换为 char**(让编译器满意)程序段错误。

f(&str);

但是以下工作正常

f(&cstr[0]);

【问题讨论】:

  • 您的代码有问题。如果可以成功编译f(&cstr[0]),那么要么cstr 不是char*,要么f 的参数s 不是char**。表达式&cstr[0] 的类型是char*(实际上和刚才的cstr 完全一样)。请显示导致错误的实际代码。如果是这个,那你用的是什么 C++ 编译器?

标签: c++ pointers string


【解决方案1】:

第一行 line 定义了一个四个字节的数组。这两个是等价的:

char str[4] = "abc";
char str[4] = {'a', 'b', 'c', 0};

第二行声明了一个指向内存位置的指针,其中包含字节'a'、'b'、'c'和0。这两个是等价的:

char *cstr = {"abc"};
char *cstr = "abc";

您的问题来自混合char[]char*。如果函数接受char**,则必须创建char* 以获取以下地址:

char str[4] = "abc";
char *cstr = str;
f(&cstr);

【讨论】:

  • 好吧,他特别说f(&cstr) 会导致段错误......尽管它确实不应该。我怀疑我们没有实际的代码。
【解决方案2】:

这是一个示例,说明指针和数组在 C 中是如何等效的。特别是:数组衰减为指针的规则不会递归应用

这意味着数组可以用作指针,但指向数组的指针不能用作指针。这就是你在这里所经历的。这就是为什么当您没有将 &str 显式转换为 char** 时编译器会抱怨类型不匹配的原因。这应该是您发现问题的第一个线索。

这导致段错误的原因是:数组自动衰减到指针的方式是通过转换为其第一个元素的地址。指向数组的指针同样是指向数组第一个元素地址的指针。所以指向数组的指针和作为指针的数组是一回事。换句话说,当作为指针传递时,str 的值与 &str 相同。所以如果你试图把 &str 变成一个指向指针的指针,它是行不通的,因为它只是一个(单级)指针。

例如,

void f(char** pp);
void g(char* p);

char[] str = "abcd"; // Lets say this is allocated at address 0x1234
g(str); // Value of p in g is 0x1234 (by automatic conversion of char[4] to char*)

char* p_str = &str; // Value of p_str is 0x1234
g(p_str); // Value of p in g is again 0x1234 

f(str);  // Illegal, no conversion of char[] to char** (obvious)
f(p_str); // Illegal, no conversion of char* to char** (obvious)
f(&str); // Illegal, no conversion of char*[4] to char** (less obvious)

f((char**)p_str); // Ok, now you're overriding the typecheck

但是在最后一次调用f((char**)p_str) 之后,f 中 pp 的值仍然是 0x1234,因为你没有修改 p_str 的值,你只是抑制了类型检查器的抱怨。这意味着 *pp 将是 'a',而不是指向包含 'a' 的地址的指针。这就是为什么当 f 尝试执行 **pp 时会出现段错误。

【讨论】:

    【解决方案3】:

    这里的大括号实际上是一条错误的线索。

    str 是一个初始化的数组,而不是一个指针:在你的例子中没有实际的指针 variable 持有str 的地址,所以你不能取它的地址,因此表达式&str 产生编译错误。

    相比之下,cstr是一个指针变量,里面保存着一个字符串常量的地址,这个指针变量的地址是可以取的。

    【讨论】:

    • 你可以取一个数组的地址。结果是指向所述数组的指针。在这种情况下,此类指针的类型将是char(*)[4]
    • 是的 Pavel,这就是我在使用 f(&str); 时遇到的编译器错误。类似“char** 不匹配 char(*)[4]”
    【解决方案4】:

    所以,&x 为您提供指向 x 的指针。但是指向数组的指针数组是一回事。左值表达式规则的一个例外强化了这一点,在 & 运算符的情况下,当应用于数组时,表达式类型不会转换为“指向...的指针”。 (6.2.2.1,ANSI 9899-1990。)

    这意味着当str 是一个实际数组时,str&str 是同一个东西。但是&p 哪里p 真的是一个指针会给你一个双间接指针,即**p

    如果标准只是说“& 在数组被忽略之前”,这会更清楚,而且我认为 dmr 关于 C 的出版物曾经真的这么说。相反,ANSI 将其表述为转换规则,与 & 运算符的定义相去甚远。

    【讨论】:

      【解决方案5】:

      你可以试试

      char str[4] = {'a', 'b', 'c', 0};
      

      char str[4];
      sprintf(str, "abc");
      

      【讨论】:

      • 这与char str[4] = "abc" 没有任何不同。在strcpy 可以使用的地方使用sprintf 也是一个坏主意。
      猜你喜欢
      • 2016-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-09
      • 1970-01-01
      • 2020-07-14
      • 2014-08-13
      • 2012-05-28
      相关资源
      最近更新 更多