打印一个char指针......会发生什么?

时间:2014-12-23 19:29:45

标签: c string pointers char

我是C的新手,我有一个关于char指针及其打印内容的问题。看一看:

int main()
{
char *p1="ABCD";
p1="EFG";
printf ("%s",p1);
return 0;
}

它将打印EFG

现在:

int main()
{
char *p1="ABCD";
//p1="EFG";
printf ("%s",p1);
return 0;
}

它会给你ABCD

我不知道的是*p1究竟是什么? 它是一个包含char值的地址吗? 是char吗? 现在*p1中的内容是什么?为什么是const

8 个答案:

答案 0 :(得分:3)

来自C标准:

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf

EXAMPLE 8 The declaration

  char s[] = "abc", t[3] = "abc";
  defines ‘‘plain’’ char array objects s and t whose elements are initialized with character string literals.

This declaration is identical to

  char s[] = { 'a', 'b', 'c', '\0' },
  t[] = { 'a', 'b', 'c' };

The contents of the arrays are modifiable. On the other hand, the declaration

  char *p = "abc";

defines p with type ‘‘pointer to char’’ and initializes it to point to an object
with type ‘‘array of char’’ with length 4 whose elements are initialized with a
character string literal. If an attempt is made to use p to modify the contents
of the array, the behavior is undefined.

换句话说:

1)char *p1;声明一个指针变量(p1)。指针p1可以改变。

2)char *p1 = "ABCD";声明p1(与" 1"相同)并初始化它指向的数据(将其初始化为只读,5元素字符数组" ABCD \ 0"。)

所以你可以改变地址" p1"指向(你可以指向" EFG",将它指定为NULL等等)。但是你不能安全地改变数据本身。您可能会受到访问违规行为"如果你试图覆盖" ABCD"。确切的行为是"未定义" - 任何都可能发生。

3)char p2[] = "ABCD";声明一个变量(p2),它是一个数组。它分配5个字符,并将数据初始化为" ABCD \ 0"。

数组是读写的(你可以改变数组中的数据),但变量" p2"无法更改(您无法将p2更改为指向其他地址 - 因为它不是指针)。

4)那么"差异"在char *指针和char数组之间[]?这是一个很好的讨论:

http://c-faq.com/aryptr/aryptrequiv.html

答案 1 :(得分:1)

p1是一个char指针,用于存放基地址起始地址第一个元素的地址=运算符为字符串 分配的em>。

在你的第一个代码中,你已经为它分配了基本地址“ABCD”,后来是“EFG”的基地址[覆盖了以前的值]并最终打印出来。因此,打印出最新值[“EFG”]。

在第二种情况下,您将分配基本地址“ABCD”并进行打印。所以它会打印ABCD。 也许值得一提的是,%s中的printf()格式说明符需要以p1为指向的空终止字符串的起始地址

根据const部分,p1指向的字符串在这种情况下是常量,因为字符串文字通常是存储在只读存储器位置。意味着,不允许更改值p[1] = 's'。但是,指针p1不是const,因此可以正确地将其重新分配给新值p1="EFG";

答案 2 :(得分:1)

p1是一个char指针,它保存编译器在内存中放置“ABCD”的地址。地址是数组中的第一个字符。

当你有char *p1 = "ABCD";时,你只需要分配p1中保存的地址的值。 当您重新分配p1 = "EFG";时,您正在重新分配指针以保存新地址(“EFG”所在的位置)

printf ("%s",p1);打印位于p1个位置的内存内容。

答案 3 :(得分:1)

最初p1被声明为char指针并指向" ABCD" (" ABCD"的基地址)。

稍后指针指向" EFG" (包含&#34的基地址; EFG")

+----+      +---+
|ABCD|      |EFG|
+----+      +---+
 1000        2000

char *p1="ABCD";
         +----+
before   |1000|
         +----+
          p1
p1="EFG";
After    +----+
         |2000|
         +----+
          p1

答案 4 :(得分:1)

int main()
{
    char *p1="ABCD";
    p1="EFG";
    printf ("%s",p1);
    return 0;
}

这缺少必需的#include <stdio.>。没有它,你的编译器可能会让你忘记调用printf,但它不能保证工作。还有一个小问题:int main()应为int main(void)

在这个程序中实际上发生了很多事情,其中​​一些是相当微妙的。

char *p1 = "ABCD";

"ABCD"是一个字符串文字。它指定类型为char[5]的匿名数组对象(对于您指定的字符为4,对于标记字符串结尾的'\0'空字符为1)。该对象具有静态存储持续时间,这意味着它在程序的整个执行期间存在(与局部变量不同,例如,当它超出范围时不再存在(&#39;略微过于简单化))。

在大多数情况下,数组表达式被隐式转换为指向其第一个元素的指针。因此,p1被初始化为指向该字符'A',即该匿名数组对象的第一个字符。

p1 定义为const char *p1 = ...。它实际上并不是必需的,但它将帮助编译器捕获任何修改数组对象的尝试。 (该对象不是const,但修改它有未定义的行为。)

p1 = "EFG";

现在p1中存储的值被破坏并被新的指针值替换,这次指向字符串文字'E'的{​​{1}}。 (所以初始化没有意义,但那没关系。)

"EFG"

这里我们将printf("%s", p1); (指针值)的值传递给p1函数。

此时,printf的值为*p1,类型为'E'。但char能够打印整个字符串printf。它使用指针算术来执行此操作。在"EFG"的实现中的某处,有一个循环,它接受传入的指针值,取消引用它以获取要打印的字符值,然后递增指针使其指向下一个字符字符串(printf)。此循环继续,直到它到达标记字符串结尾的'F'空字符;该空字符未打印。

由于阵列在某种意义上是“二等公民”#34;在C中,对数组对象的大多数操作都是这样完成的,使用指向数组元素的指针来遍历数组。 (您也可以使用索引符号'\0',这基本上是相同的。)arr[i]无法直接访问数组对象本身;它依赖于指针(到它的第一个元素)来确定数组在内存中的位置,并依赖于printf终结符来确定字符串的结束位置。

第二个程序是相同的,除了'\0'未重新分配,因此打印字符串p1

C中的数组和指针之间的关系可能令人困惑。 comp.lang.c FAQ的第6节非常好地解释了它。

答案 5 :(得分:1)

  

我不知道究竟是*p1是什么?   它是一个包含char值的地址吗?它是一个炭?

如果您在声明中谈论*p1

char *p1 = "ABCD";    

然后*表示p1是指向char的指针(在这种情况下实际上是const char)。 p1只指向字符串文字ABCD的第一个字符。

如果您在

中询问*p1
printf("%c", *p1); 

然后*这里是间接运算符,*p1表示字符p1的值指向A*p1相当于p1[0] 声明

 p1 = "DEF";  

p1指向字符串文字DEF的第一个字符。

  

为什么const

字符串文字存储在内存的只读部分中。

char *p1 = "ABCD";  

相当于

char const *p1 = "ABCD";

这意味着您无法修改字符串文字。

*p1 = 'a'; // WRONG. Invokes undefined behavior.  

答案 6 :(得分:0)

  

我不知道的是* p1究竟是什么!它是一个包含char值的地址吗?它是一个炭?现在什么是* p1?

*p1的类型为char。它的值是字符'A'

  

为什么是const

字符串文字(如"ABCD")放在只读内存中。通过p修改它们是导致未定义的行为的原因。这就是*p1只读的原因,即它是const

答案 7 :(得分:0)

  

我不知道的是* p1究竟是什么!它是一个包含char值的地址吗?它是一个炭?现在什么是* p1?

*p1的值为p1[0],即您的第一个程序中值char的{​​{1}}和第二个程序中的值'E'

  

为什么是常量?

C中不是'A'(它在C ++中),但在C中指定字符串文字是不可修改的,这意味着修改const的尝试会调用未定义的行为。