15
char *p = "some string"   

创建一个指针 p 指向包含字符串的块。

char p[] = "some string" 

创建一个字符数组并在其中包含文字。

而且第一个是常量声明,和二维数组一样吗?

有什么区别

char **p,char *p[],char p[][]. 

我读到了一些关于 char **p 创建指针数组的信息,因此与char p[][]存储指针值相比,它具有开销。

argv前两个声明创建常量数组。当我尝试修改in的内容时,我没有收到任何运行时错误main(int argc,char **argv)。是因为它们是在函数原型中声明的吗?

4

3 回答 3

17

普通声明(不是函数参数)

char **p;声明一个指向char. 它为指针保留空间。它不为指向的指针或任何char.

char *p[N];声明一个包含N个指向char. 它为N个指针保留空间。它不为任何char. N必须显式提供,或者在带有初始化程序的定义中,通过让编译器计算初始化程序来隐式提供。

char p[M][N];声明一个由N组成的M个数组组成的数组。它为M •<i>N保留空间。不涉及指针。并且必须显式提供,或者在带有初始化程序的定义中,通过让编译器计算初始化程序来隐式提供。 charcharMN

函数参数中的声明

char **p声明一个指向char. 调用函数时,会为该指针提供空间(通常在堆栈或处理器寄存器中)。没有为指向指针或任何char.

char *p[N]调整为char **p,所以同上。的值N被忽略,并且N可能不存在。(有些编译器可能会计算N,所以,如果它是一个有副作用的表达式,例如printf("Hello, world.\n"),则在调用函数时可能会出现这些影响。C 标准对此并不清楚。)

char p[M][N]被调整为,所以它是一个指向Nchar (*p)[N]数组的指针。的值被忽略,并且可能不存在。必须提供。调用函数时,会为指针提供空间(通常在堆栈或处理器寄存器中)。没有为N的数组保留空间。 charMMN char

argv

argv是由调用的特殊软件创建的main。它充满了软件从“环境”中获得的数据。您可以修改其中的char数据。

在您的定义char *p = "some string";中,您不得修改p指向的数据,因为 C 标准规定不得修改字符串文字中的字符。(从技术上讲,它说的是,如果你尝试,它不会定义行为。)在这个定义中,p不是数组;它是指向char数组中第一个的指针,char它们位于字符串文字中,并且不允许修改字符串文字的内容。

在您的定义char p[] = "some string";中,您可以修改p. 它们不是字符串文字。在这种情况下,字符串文字实际上在运行时不存在;它只是用来指定如何p初始化数组的东西。p初始化后,您可以对其进行修改。

设置的数据argv以允许您修改它的方式设置(因为 C 标准指定了这一点)。

于 2013-10-11T19:18:23.423 回答
6

从内存寻址视图看的更多差异描述如下,

I.char **p; p是双指针类型char

宣言:

char a = 'g';
char *b = &a;
char **p = &b;


   p                    b                    a     
+------+             +------+             +------+
|      |             |      |             |      |              
|0x2000|------------>|0x1000|------------>|   g  | 
|      |             |      |             |      |
+------+             +------+             +------+
 0x3000               0x2000               0x1000
Figure 1: Typical memory layout assumption   

在上面的声明中,achar包含字符的类型g。指针b包含现有字符变量的地址a。现在b是 address0x1000并且*b是 character g。最后的地址b分配给p,因此a是字符变量,b是指针,p是指向指针的指针。这意味着a包含值,b包含地址和p包含地址的地址,如下图所示。

在这里,sizeof(p) = sizeof(char *)在各自的系统上;

二、char *p[M]; p是字符串数组

宣言:

char *p[] = {"Monday", "Tuesday", "Wednesday"};


      p
   +------+  
   | p[0] |       +----------+
0  | 0x100|------>| Monday\0 |              
   |      |       +----------+
   |------|       0x100
   | p[1] |       +-----------+
1  | 0x200|------>| Tuesday\0 |
   |      |       +-----------+
   |------|       0x200
   | p[2] |       +-------------+
2  | 0x300|------>| Wednesday\0 |
   |      |       +-------------+ 
   +------+       0x300
Figure 2: Typical memory layout assumption

在此声明中,p是由 3 个类型的指针组成的数组char。暗示数组p可以容纳 3 个字符串。每个字符串(Monday, Tuesday & Wednesday)位于内存中的某个位置(0x100, 0x200 & 0x300),地址分别位于数组p(p[0], p[1] & p[2])。因此它是指针数组。

笔记:char *p[3];

1. p[0], p[1] & p[2] are addresses of strings of type `char *`.
2. p, p+1 & p+2 are address of address with type being `char **`.
3. Accessing elements is through, p[i][j] is char; p[i] is char *; & p is char **

这里sizeof(p) = Number of char array * sizeof(char *)

三、char p[M][N]; p是固定长度的字符串数组,其维度为M x N

宣言:

char p[][10] = {Monday, Tuesday, Wednesday};


  p  0x1 2 3 4 5 6 7  8  9  10
    +-------------------------+
 0  | M  o n d a y \0 \0 \0 \0|     
 1  | T  u e s d a  y \0 \0 \0| 
 2  | W  e d n e s  d  a  y \0|
    +-------------------------+
 Figure 3: Typical memory layout assumption

在这种情况下,数组p包含 3 个字符串,每个字符串包含 10 个字符。形成内存布局,我们可以说p是一个大小为 的二维字符数组,MxN3x10我们的示例中。这对于表示长度相等的字符串很有用,因为与声明相比,当字符串包含少于 10 个字符时可能会浪费内存char *p[],而声明没有内存浪费,因为未指定字符串长度,并且对于表示长度不等的字符串很有用。

访问元素与上述情况类似,p[M]是第 M 个字符串 & p[M][N] 是第 M 个字符串的第 N 个字符。这里sizeof(p) = (M rows * N columns) * sizeof(char)的二维数组;

于 2013-11-04T08:35:58.463 回答
0
  • ainchar* a是指向字符数组的指针,a可以修改。
  • binchar b[]是字符数组。 b无法修改。

它们是兼​​容的—— b可以自动衰减a赋值和表达式中,但不能反过来。

当您使用char** p时,char* p[]情况char p[][]非常相似,只是更多的间接级别。

于 2013-10-11T18:58:54.847 回答