c语言 - 在字符指针数组的情况下,'array name'是什么意思?



在我的代码中:

char *str[] = {"forgs", "do", "not", "die"};
printf("%d %d", sizeof(str), sizeof(str[0]));  

我得到的输出是12 2,所以我的疑问是:

  1. 为什么有区别?
  2. strstr[0]都是char指针,对吗?

虽然这个问题已经被回答并接受了,但我正在添加一些更多的描述(也回答了原来的问题),我想这对新用户会有帮助。(正如我搜索的那样,这个描述在其他任何地方都没有解释(至少在stackoverflow上),因此我现在添加。

首读:sizeofOperator

6.5.3.4 sizeof操作符,1125:
当对数组类型应用sizeof运算符时,结果是该数组的总字节数。

根据此,当sizeof应用于静态数组标识符的名称时(而不是通过malloc分配的),结果是以字节为单位的整个数组的大小,而不仅仅是地址。这是数组名称被转换/衰减为指向数组第一个元素的指针的少数例外之一,这是可能的,因为实际数组大小是固定的,并且在编译时sizeof操作符求值时已知。

为了更好地理解它,考虑下面的代码:

#include<stdio.h>
int main(){
char a1[6],       // One dimensional
a2[7][6],     // Two dimensional 
a3[5][7][6];  // Three dimensional
printf(" sizeof(a1)   : %lu n", sizeof(a1));
printf(" sizeof(a2)   : %lu n", sizeof(a2));
printf(" sizeof(a3)   : %lu n", sizeof(a3));
printf(" Char         : %lu n", sizeof(char));
printf(" Char[6]      : %lu n", sizeof(char[6]));
printf(" Char[5][7]   : %lu n", sizeof(char[7][6]));
printf(" Char[5][7][6]: %lu n", sizeof(char[5][7][6]));
return 1;
} 

其输出:

sizeof(a1)   : 6 
sizeof(a2)   : 42 
sizeof(a3)   : 210 
Char         : 1 
Char[5]      : 6 
Char[5][7]   : 42 
Char[5][7][6]: 210 

检查上面在@codepad工作,注意char的大小是一个字节,如果你在上面的程序中将char替换为int,那么每个输出将乘以你机器上的sizeof(int)

char* str[]char str[][]的区别以及它们在内存中的存储方式

Declaration-1:char *str[] = {"forgs", "do", "not", "die"};

在此声明中,str[]是指向char的指针的数组。每个索引str[i]都指向{"forgs", "do", "not", "die"};中字符串的第一个字符,
逻辑上str应该按照以下方式在内存中排列:

Array Variable:                Constant Strings:
---------------                -----------------
str:                       201   202   203   204  205   206
+--------+                +-----+-----+-----+-----+-----+-----+
343    |        |= *(str + 0)    | 'f' | 'o' | 'r' | 'g' | 's' | ''|
| str[0] |-------|        +-----+-----+-----+-----+-----+-----+
| 201    |       +-----------▲
+--------+                  502   503  504
|        |                +-----+-----+-----+
347    | str[1] |= *(str + 1)    | 'd' | 'o' | ''|
| 502    |-------|        +-----+-----+-----+
+--------+       +-----------▲
|        |                  43    44    45    46
351    | 43     |                +-----+-----+-----+-----+
| str[2] |= *(str + 2)    | 'n' | 'o' | 't' | ''|
|        |-------|        +-----+-----+-----+-----+
+--------+       +-----------▲
355    |        |
| 9002   |                 9002  9003   9004 9005
| str[3] |                +-----+-----+-----+-----+
|        |= *(str + 3)    | 'd' | 'i' | 'e' | ''|
+--------+       |        +-----+-----+-----+-----+
+-----------▲

Diagram: shows that str[i] Points to first char of each constant string literal. 
Memory address values are assumption.

注意:str[]存储在连续内存分配中,每个字符串以随机地址存储在内存中(而不是在连续空间中)。

[答案]

根据Codepad以下代码:

int main(int argc, char **argv){
char *str[] = {"forgs", "do", "not", "die"};
printf("sizeof(str): %lu,  sizeof(str[0]): %lun", 
sizeof(str), 
sizeof(str[0])
);  
return 0;
}

输出:

sizeof(str): 16,  sizeof(str[0]): 4
  • 在此代码中,str是一个包含4字符地址的数组,其中每个char*的大小为4字节,因此根据上面的引用,数组的总大小为4 * sizeof(char*)= 16字节。

  • str的Datatype为char*[4]

  • str[0]只是指向char的指针,所以它有四个字节。str[i]的Datetype是char*.

(注意:在某些系统地址中可以是2字节或8字节)

关于输出,还应该阅读glgll对问题的评论:

在任何架构中,第一个值应该是第二个值的4倍。在32位机器上,您应该得到16 4,在64位机器上得到32 8。在一个很旧的上面或者在嵌入式系统上,您甚至可能得到8 2,但永远不会得到12 2,因为数组包含4个相同大小的元素

附加说明:

  • 因为每个str[i]指向一个char*(和字符串)是变量,str[i]可以被分配一个新的字符串地址,例如:str[i] = "yournewname";i = 0 to < 4有效。

还有一点需要注意:

  • 在上面的例子中,str[i]指向不能修改的常量字符串字面值;因此,str[i][j] = 'A'是无效的(我们不能在只读内存上写),这样做将是一个运行时错误。
    但是假设str[i]指向一个简单的char数组,那么str[i][j] = 'A'可以是一个有效的表达式。
    考虑以下代码:

    char a[] = "Hello"; // a[] is simple array
    char *str[] = {"forgs", "do", "not", "die"};
    //str[0][4] = 'A'; // is error because writing on read only memory
    str[0] = a;
    str[0][5] = 'A'; // is perfectly valid because str[0] 
    // points to an array (that is not constant)
    

查看这里的工作代码:Codepad

Declaration-2:char str[][6] = {"forgs", "do", "not", "die"};:

这里str是一个大小为4 * 6的二维字符数组(每行大小相等)。(记住这里你必须明确地在str的声明中给出列值,但行是4,因为字符串的数量是4)
在内存中str[][]将类似于下图:

str
+---201---202---203---204---205---206--+
201                 | +-----+-----+-----+-----+-----+-----+|   
str[0] = *(str + 0)--►| 'f' | 'o' | 'r' | 'g' | 's' | ''||
207                 | +-----+-----+-----+-----+-----+-----+|
str[1] = *(str + 1)--►| 'd' | 'o' | ''| ''| ''| ''||
213                 | +-----+-----+-----+-----+-----+-----+|
str[2] = *(str + 2)--►| 'n' | 'o' | 't' | ''| ''| ''||
219                 | +-----+-----+-----+-----+-----+-----+|
str[3] = *(str + 3)--►| 'd' | 'i' | 'e' | ''| ''| ''||
| +-----+-----+-----+-----+-----+-----+|
+--------------------------------------+
In Diagram:                                 
str[i] = *(str + i) = points to a complete i-row of size = 6 chars. 
str[i] is an array of 6 chars.

这种二维数组在内存中的排列被称为Row-Major:线性存储器中的多维数组是这样组织的:一行接一行地存储。这是C编程语言使用的方法。

注意两个图的不同之处。

  • 在第二种情况下,完整的二维字符数组被分配到连续内存中。
  • 对于任何i = 0 to 2,str[i]str[i + 1]的值相差6字节(即等于一行的长度)。
  • 图中双边界线表示str代表完整的6 * 4 = 24个字符。

现在考虑类似的代码你张贴在你的问题为二维字符数组,检查在Codepad:

int main(int argc, char **argv){
char str[][6] = {"forgs", "do", "not", "die"};
printf("sizeof(str): %lu,  sizeof(str[0]): %lun", 
sizeof(str), 
sizeof(str[0])
);
return 0;
}

输出:

sizeof(str): 24,  sizeof(str[0]): 6

根据sizeof运算符对数组的处理,当应用二维数组的大小为时,应该返回整个数组的大小,即24字节。

  • 如我们所知,sizeof操作符在应用数组名时返回整个数组的大小。因此,对于sizeof(str),它返回= 24,即完整的2D字符数组的大小,由24个字符(6-cols* 4-rows)组成。

  • 在这里,str的声明类型是char[4][6]

  • 一个更有趣的点是str[i]代表一个数组聊天,它的类型是char[6]sizeof(str[0])是完整数组的大小= 6(行长度)。

附加说明:

  • 在第二个声明中str[i][j]不是常量,它的内容可以改变,例如str[i][j] = 'A'是一个有效的操作。

  • str[i]char[6]类型的char数组的名称,str[i]是一个常量,例如str[i] = "newstring"是非法操作(感染会导致编译时错误)。

两个声明之间的另一个重要区别:

在<<p> strong> Declaration-1 :char *str[] = {"forgs", "do", "not", "die"};,&str的类型是char*(*)[4],它的char指针数组地址。在<<p> strong> Declaration-2 :char str[][6] = {"forgs", "do", "not", "die"};,&str类型为char(*)[4][6],其地址为4行6位二维字符数组

如果想要读取一维数组的类似描述:sizeof(&array)返回什么?

在大多数情况下,数组名称将衰减为其第一个元素的地址值,并且类型与指向元素类型的指针相同。因此,您会期望裸str的值等于&str[0],类型为指针指向指向char的指针。

然而,sizeof的情况并非如此。在本例中,数组名称保持了sizeof的类型,即指向char的4个指针数组。

sizeof返回类型为size_t。如果你有一个C99编译器,你可以在格式字符串中使用%zu来打印sizeof返回的值。

我的电脑上是16 4,我可以解释一下:strchar*的数组,所以sizeof(str)==sizeof(char*)*4

我不知道为什么你得到12 2

这两个指针是不同的。str是一个array of char pointers,在你的例子中是一个(char*[4]),str[0]是一个char pointer

第一个sizeof返回包含四个char指针的大小,第二个返回char*的大小。
在我的测试中,结果是:

sizeof(str[0]) = 4   // = sizeof(char*)
sizeof(str) = 16  
= sizeof(str[0]) + sizeof(str[1]) + sizeof(str[2]) + sizeof(str[3])
= 4 * sizeof(char*)  
= 4 * 4
= 16

最新更新