【问题标题】:Character Pointers in CC中的字符指针
【发布时间】:2013-01-15 03:18:12
【问题描述】:
 #include <stdio.h>

  int main(void){

  char *p = "Hello";  
  p = "Bye";              //Why is this valid C code? Why no derefencing operator?

  int *z;
  int x;
  *z = x
  z* = 2                 //Works
  z  = 2                 //Doesn't Work, Why does it work with characters?

 char *str[2] = {"Hello","Good Bye"};

 print("%s", str[1]);      //Prints Good-Bye.     WHY no derefrencing operator?
                          // Why is this valid C code? If I created an array with pointers
                         // shouldn't the element print the memory address and not the string?
  return 0;

  }

我的问题与 cmets 一起列出。在一般情况下,我无法理解字符数组和指针。特别是为什么我可以在没有取消引用运算符的情况下访问它们。

【问题讨论】:

  • 对于 str[1],会发生解除引用。在内部它将像 *(str + 1)
  • 来到 p = "Bye" 实际上 p 是指向常量的指针,所以如果你喜欢 *p = 'a';它不会在编译时允许你,但因为你做了 p = "Bye" ,它会给 p 一个新地址所以它会工作
  • @user93353。我确实买了一本书。此代码来自一本书。感谢您富有洞察力的 cmets。不是
  • 这本书没有解释发生了什么?
  • 你需要买一本更好的书——也许是 Kernighan 和 Ritchie?也许其中之一 - stackoverflow.com/questions/693210/…

标签: c arrays pointers character


【解决方案1】:

在一般情况下,我无法理解字符数组和指针。

这对于初级 C 程序员来说很常见。大约在 1985 年,我也有同样的困惑。

p = "Bye";

由于 p 被声明为 char*,p 只是一个包含 char 内存地址的变量。上面的赋值将 p 的值设置为常量字符串“Bye”的第一个字符的地址,即字母“B”的地址。

z  = 2

z 被声明为 char*,因此您唯一可以分配给它的是 char 的内存地址。您不能将 2 分配给 z,因为 2 不是 char 的地址,它是一个常量整数值。

print("%s", str[1]);

在这种情况下,str 被定义为一个包含两个 char* 变量的数组。在您的打印语句中,您将打印其中的第二个,即字符串“Good Bye”中第一个字符的地址。

【讨论】:

  • 所以如果我打印字符串“Good Bye”中第一个字符的地址,为什么会打印Good bye?这就是让我困惑的部分。
  • @Vlad:%s 说明符不只是查看第一个字符('G')。之后它会继续在内存地址中打印字符('o',然后是'o'等)。当它看到内容为字节值 0(零)的内存地址时停止,表示文本字符串的结尾。
【解决方案2】:

当您键入“Bye”时,您实际上是在创建所谓的String Literal。这是一个特殊情况,但本质上,当你这样做时

p = "Bye";

您正在做的是将此字符串文字的 地址 分配给p(字符串本身由编译器以与实现相关的方式存储(我认为))。正如 Richard J. Ross III 所解释的那样,从技术上讲,它指向 char 数组的第一个元素。

由于是特例,因此不适用于其他类型。

顺便说一句,对于像char *p = "Hello"; 这样的行,您可能会收到编译器警告。您应该需要将它们定义为 const char *p = "Hello";,因为如链接所述,修改它们是未定义的


关于打印代码。

print("%s", str[1]); 

这个不需要解引用操作,因为在内部%s需要一个指针(特别是char *)来传递,因此解引用由@987654329完成@。当 printf 需要一个指针时,您可以通过传递一个值来测试它。当它试图取消引用它时,您应该遇到运行时崩溃。

【讨论】:

  • 您没有存储文字本身的地址 - 您(在几乎所有最近的编译器中)将第一个元素的地址存储在静态分配的空终止字符数组中。在编译器本身之外没有字符串文字这样的东西。
  • 那么如果我分配字符串文字的地址,为什么在打印该地址的内容时仍然不需要 *?
  • @RichardJ.RossIII 非常正确,但差异很小,我觉得我的版本可能更容易被新手理解。
  • @Vlad: 你不需要 * 因为 printf %s 说明符知道它应该得到一个指向字符的指针。
  • 我知道它是空终止字符数组的第一个元素,老实说,语法让我感到困惑。
【解决方案3】:
 p = "Bye"; 

是将文字的地址分配给指针。

array[n]

操作符的工作方式与将指针“array”的取消引用增加 n 类似。它不一样,但它是这样工作的。

【讨论】:

  • “字面量的地址”其实就是字面量第一个元素的地址
【解决方案4】:

记住"Hello""Bye"都是char *而不是char
所以这行,p="Bye"; 意味着指针 p 指向一个 const char *i.e."Bye"
但在下一种情况下,int *
*z=2 意味着

`z` 指向的 `int` 被赋值为 2

同时,z=2 表示指针 z 指向相同的 int,由 2 指向。但是,2 不是指向其他 int pointerints。所以,编译器标记错误

【讨论】:

  • "all are char *" 从技术上讲,它们是 char 数组,而不是指针。
  • char 数组,可以,但也可以表示为 char *
  • 一个数组表达式可以隐式转换为指向其第一个元素的指针,是的
【解决方案5】:

您有些困惑:它确实适用于字符,就像它适用于整数等一样。

不能使用的是字符串,因为它们是字符数组,并且数组只能使用它们的第一个元素的地址存储在变量中。

稍后,您创建了一个字符指针数组,或一个字符串数组。这意味着该数组的第一个元素是一个字符串,第二个元素也是一个字符串。当涉及到打印部分时,您使用的是数组的第二个元素。所以,不出所料,第二个字符串被打印出来了。

如果你这样看,你会发现语法是一致的。

【讨论】:

  • "数组只能使用第一个元素的地址存储在变量中。"不,你可以有一个数组类型的变量。
猜你喜欢
  • 1970-01-01
  • 2021-06-28
  • 2016-10-11
  • 2012-04-10
  • 1970-01-01
  • 2013-02-16
  • 1970-01-01
相关资源
最近更新 更多