在数组char指针的情况下,'数组名称'是什么意思?

Nit*_*ess 22 c pointers sizeof

在我的代码中:

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

我得到了输出12 2,所以我怀疑是:

  1. 为什么会有区别?
  2. 这两个strstr[0]是字符指针,对不对?

Gri*_*han 63

通过这个问题已经得到了回答和接受,但我正在添加一些更多的描述(也回答原始问题),我想这将对新用户有所帮助.(当我搜索时,这个描述在其他任何地方都没有解释(至少在stackoverflow上)因此我现在正在添加.

首先阅读:运营商 sizeof

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;
} 
Run Code Online (Sandbox Code Playgroud)

它的输出:

 sizeof(a1)   : 6 
 sizeof(a2)   : 42 
 sizeof(a3)   : 210 
 Char         : 1 
 Char[5]      : 6 
 Char[5][7]   : 42 
 Char[5][7][6]: 210 
Run Code Online (Sandbox Code Playgroud)

检查上面的@ codepad工作,通知大小char是一个字节,你在上面的程序中替换char,int然后每个输出将sizeof(int)在你的机器上乘以.

两者之间的差异char* str[]以及char str[][]两者如何存储在内存中

声明-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' | '\0'|
        | str[0] |-------|        +-----+-----+-----+-----+-----+-----+
        | 201    |       +-----------?
        +--------+                  502   503  504
        |        |                +-----+-----+-----+
 347    | str[1] |= *(str + 1)    | 'd' | 'o' | '\0'|
        | 502    |-------|        +-----+-----+-----+
        +--------+       +-----------?
        |        |                  43    44    45    46
 351    | 43     |                +-----+-----+-----+-----+
        | str[2] |= *(str + 2)    | 'n' | 'o' | 't' | '\0'|
        |        |-------|        +-----+-----+-----+-----+
        +--------+       +-----------?
 355    |        |
        | 9002   |                 9002  9003   9004 9005
        | str[3] |                +-----+-----+-----+-----+
        |        |= *(str + 3)    | 'd' | 'i' | 'e' | '\0'|
        +--------+       |        +-----+-----+-----+-----+
                         +-----------?


Diagram: shows that str[i] Points to first char of each constant string literal. 
Memory address values are assumption.
Run Code Online (Sandbox Code Playgroud)

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

[回答]

根据Codepad以下代码:

int main(int argc, char **argv){
    char *str[] = {"forgs", "do", "not", "die"};
    printf("sizeof(str): %lu,  sizeof(str[0]): %lu\n", 
            sizeof(str), 
            sizeof(str[0])
    );  
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

sizeof(str): 16,  sizeof(str[0]): 4
Run Code Online (Sandbox Code Playgroud)
  • 在这段代码中str是一个4个字符地址的数组,每个地址char*大小为4字节,因此根据上面的引用,数组的总大小是4 * sizeof(char*)= 16字节.

  • 数据类型strchar*[4].

  • str[0]只是指向char的指针,所以它的四个字节.日期类型str[i]char*.

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

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

无论你是什么架构,第一个值应该是第二个值的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)
    
    Run Code Online (Sandbox Code Playgroud)

在这里查看工作代码:键盘

声明-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' | '\0'||
207                 | +-----+-----+-----+-----+-----+-----+|
str[1] = *(str + 1)--?| 'd' | 'o' | '\0'| '\0'| '\0'| '\0'||
213                 | +-----+-----+-----+-----+-----+-----+|
str[2] = *(str + 2)--?| 'n' | 'o' | 't' | '\0'| '\0'| '\0'||
219                 | +-----+-----+-----+-----+-----+-----+|
str[3] = *(str + 3)--?| 'd' | 'i' | 'e' | '\0'| '\0'| '\0'||
                    | +-----+-----+-----+-----+-----+-----+|
                    +--------------------------------------+
  In Diagram:                                 
  str[i] = *(str + i) = points to a complete i-row of size = 6 chars. 
  str[i] is an array of 6 chars.
Run Code Online (Sandbox Code Playgroud)

内存中2D阵列的这种排列称为行主要:线性存储器中的多维数组被组织成使得行一个接一个地存储.它是C编程语言使用的方法.

注意两个图中的差异.

  • 在第二种情况下,在继续存储器中分配完整的二维char数组.
  • 对于任何i = 0 to 2,str[i]并且str[i + 1]值是由6个字节的不同(即等于一个行的长度).
  • 此图中的双边界线str表示完整的6*4 = 24个字符.

现在考虑一下您在二维char数组问题中发布的类似代码,请在Codepad上查看:

int main(int argc, char **argv){
    char str[][6] = {"forgs", "do", "not", "die"};
    printf("sizeof(str): %lu,  sizeof(str[0]): %lu\n", 
            sizeof(str), 
            sizeof(str[0])
    );
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

sizeof(str): 24,  sizeof(str[0]): 6
Run Code Online (Sandbox Code Playgroud)

根据sizeof运算符对数组的处理,应用2-d数组大小应返回整个数组大小为24字节.

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

  • 在该声明类型strchar[4][6].

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

附加要点:

  • 在第二个声明str[i][j]中不是常量,并且其内容可以是变化的,例如str[i][j] = 'A'是有效的操作.

  • str[i]是类型的char数组的名称char[6]是一个常量,并且分配给str[i]例如str[i] = "newstring"非法操作(感染它将是编译时错误).

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

Declaration-1:中char *str[] = {"forgs", "do", "not", "die"};,类型&strchar*(*)[4],它的char指针数组的地址.

声明-2 :char str[][6] = {"forgs", "do", "not", "die"};键入的&strIS char(*)[4][6],其4行和6个COLS 2- d字符数组的地址.

如果一个人想读类似的描述为1-d阵:这是什么sizeof(&array)回报?

  • 你的引用说"......而不是数组所代表的指针的大小".数组名称不表示指针.它可以方便地衰减成指针但不会使它成为指针. (2认同)

jxh*_*jxh 8

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

但事实并非如此sizeof.在这种情况下,数组名称保持其类型sizeof,这将是4指针的数组char.

返回类型sizeof是a size_t.如果您有C99编译器,则可以使用%zu格式字符串来打印返回的值sizeof.

  • @glglgl"12 2"可能解释为`size_t`是64位,并按照我的注释传递给`%d`格式的`printf`时调用未定义的行为. (3认同)
  • 如果您的实现支持它,请使用"%zu"来打印`size_t`值.如果没有(微软可能不会),请使用`"%lu"`并将值转换为`unsigned long`.或者,如果你很懒并且已知值很小,请使用`"%d"`并转换为`int`. (2认同)

Man*_*nas 6

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

我不知道你为什么会12 2这样.