Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 字符串和字符数组的内存分配_C_String_Memory Management - Fatal编程技术网

C 字符串和字符数组的内存分配

C 字符串和字符数组的内存分配,c,string,memory-management,C,String,Memory Management,我无法理解以下代码中如何分配内存: #include<stdio.h> #include<string.h> int main() { char a[]={"text"}; char b[]={'t','e','x','t'}; printf(":%s: sizeof(a)=%d, strlen(a)=%d\n",a, sizeof(a), strlen(a)); printf(":%s: sizeof(b)=%d, strlen(b)=

我无法理解以下代码中如何分配内存:

#include<stdio.h>
#include<string.h>

int main()
{
    char a[]={"text"};
    char b[]={'t','e','x','t'};
    printf(":%s: sizeof(a)=%d, strlen(a)=%d\n",a, sizeof(a), strlen(a));
    printf(":%s: sizeof(b)=%d, strlen(b)=%d\n",b, sizeof(b), strlen(b));
    return 0;
}
通过查看内存地址和输出代码,变量b似乎放在变量a之前,这就是strlen(b)通过查找\0返回8的原因。 为什么会发生这种情况?我希望先声明变量a。

您的“b”字符数组不是以null结尾的。要理解,CARAR A[]声明相当于:

char a[] = { 't', 'e', 'x', 't', '\0' };

换句话说,strlen(b)未定义,它只是在随机内存中查找空字符(0字节)。

我没有得到相同的输出,请参见我的ideone代码段:

当我使用codepad时,我看到的输出与您不同:

也可以,编译C++编译器时,得到相同的输出:

因此,您的平台和/或编译器肯定出了问题。它可能是未定义的行为(UB),因为您的字符数组没有空终止符(\0)。无论如何

虽然a和b看起来可能相同,但这并不是因为您定义了字符数组

char a[] = "text";
此阵列在内存中的外观如下所示:

----------------------
| t | e | x | t | \0 |
----------------------

双引号表示“文本字符串”,将自动添加\0(这就是为什么大小为5)。在b中,您必须手动添加,但大小为4。b中的
strlen()。对于非空终止字符数组的编码,这在许多安全方面都是一个大问题。

该语言不保证将什么放在哪里。所以,你的实验毫无意义。这可能有效,也可能无效。该行为未定义。您的
b
不是字符串,将
strlen
与非字符串的内容一起使用是非常必要的

然而,从纯粹实用的角度来看,局部变量通常在堆栈上分配,而may moderns平台(如x86)上的堆栈向后增长,即从较高的地址到较低的地址。因此,如果您使用的是这些平台中的一个,那么您的编译器可能决定按照变量声明的顺序分配变量(
a
第一个和
b
第二个),但因为堆栈向后增长
b
在内存中的地址比
a
低。即
b
在内存中的
a
之前结束


但是可以注意到,典型的实现通常不会逐个为局部变量分配堆栈空间。相反,所有局部变量(堆栈帧)的整个内存块一次分配,这意味着我上面描述的逻辑不一定适用。然而,仍然有可能编译器仍然遵循局部变量布局的“反向”方法,即先前声明的变量稍后放置在局部内存帧中,“好像”它们是按照声明的顺序一个接一个地分配的。

我在Linux/x86上用GCC编译代码,使用-S标志查看程序集输出。这表明对我来说,b[]分配的内存地址比a[]高,所以我没有得到strlen(b)=4

在上面的代码中,$1954047348后跟$0是一个以null结尾的[]。之后的4个字节是b[]。这意味着,由于堆栈在此编译器上向下生长,因此在堆栈上b[]被推到a[]之前


如果使用-S(或等效项)进行编译,则应在比a[]更低的地址处看到b[],因此将得到strlen(b)=8。

不保证按任何特定顺序分配内存<代码>a
可以在
b
之前或之后出现,也可以彼此不在一起。这是事实。这就是为什么它在堆栈中更高。但是你真的不应该依赖于这样的期望。将strlen()与字符数组一起使用可能是危险的。@只是另一个程序员:没有比在分配的内存上调用
strlen
更危险的了。在我看来,这个问题清楚地表明OP知道这一点。问题真的是“为什么a高于b?”@Pascal:这是他的编译器或其他东西,请看我的答案。您在这里多次说“正确的输出”,但肯定
strlen(b)
is UB?@0A0D:未定义的行为。你后来(在底部)含糊地提到了它。我想我的观点是,从技术上讲,对于strlen(b)@Frexus,任何答案都可能是“正确的”:你没有说明你是如何推断b是在a之前声明的,除了你有一个加倍的单词text。这确实很奇怪,因为我展示的三种不同的编译器都没有显示这种行为。既然“字符串”不是以null结尾的,任何事情都可能发生。@0A0D,为什么说平台或编译器有问题?OP导致了未定义的行为——这当然不是他的工具的错。错,错,错。他们的编译器没有问题-在确定什么是正确的行为或其他行为时,您必须根据标准而不是编译器工作。如果你从一个错误的前提开始,世界上所有的演绎推理都不会帮助你。
:text: sizeof(a)=5, strlen(a)=4
:text: sizeof(b)=4, strlen(b)=4
:text: sizeof(a)=5, strlen(a)=4
:text: sizeof(b)=4, strlen(b)=4
char a[] = "text";
----------------------
| t | e | x | t | \0 |
----------------------
    .file   "str.c"
    .section    .rodata
    .align 4
.LC0:
    .string ":%s: sizeof(a)=%d, strlen(a)=%d\n"
    .align 4
.LC1:
    .string ":%s: sizeof(b)=%d, strlen(b)=%d\n"
    .text
.globl main
    .type   main, @function
main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $32, %esp
    movl    %gs:20, %eax
    movl    %eax, 28(%esp)
    xorl    %eax, %eax
    movl    $1954047348, 19(%esp)
    movb    $0, 23(%esp)
    movb    $116, 24(%esp)
    movb    $101, 25(%esp)
    movb    $120, 26(%esp)
    movb    $116, 27(%esp)
    leal    19(%esp), %eax
    movl    %eax, (%esp)
    call    strlen
    movl    %eax, %edx
    movl    $.LC0, %eax
    movl    %edx, 12(%esp)
    movl    $5, 8(%esp)
    leal    19(%esp), %edx
    movl    %edx, 4(%esp)
    movl    %eax, (%esp)
    call    printf
    leal    24(%esp), %eax
    movl    %eax, (%esp)
    call    strlen
    movl    $.LC1, %edx
    movl    %eax, 12(%esp)
    movl    $4, 8(%esp)
    leal    24(%esp), %eax
    movl    %eax, 4(%esp)
    movl    %edx, (%esp)
    call    printf
    movl    $0, %eax
    movl    28(%esp), %edx
    xorl    %gs:20, %edx
    je  .L2
    call    __stack_chk_fail
.L2:
    leave
    ret
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
    .section    .note.GNU-stack,"",@progbits