我想知道是否存储了char *,以及如何进行用户输入,例如他的名字然后用printf打印出来......
char *name = "Adam";
/*where does this store itself?
does the memory allocate the necessary memory stroage for this
please explain this simply and fully if you can
*/
//and btw
char name2[] = "Adam";
//what is the diffrence between name and name2
答案 0 :(得分:4)
字符串文字存储的确切位置主要取决于单个实现;唯一的要求是文字对整个程序是可见的,并且在程序启动时分配,直到程序终止为止。
某些平台可能会将文字存储在不同的内存段(例如.rodata
)中。
至于
之间的区别char *name = "Adam";
和
char name2[] = "Adam";
图片可能会有所帮助。以下是我的特定系统的实现方式:
Item Address 00 01 02 03
---- ------- -- -- -- --
"Adam" 0x400ac0 41 64 61 6d Adam
0x400ac4 00 22 41 64 ."Ad
name 0x7fff39dbdb78 c0 0a 40 00 ..@.
0x7fff39dbdb7c 00 00 00 00 ....
name2 0x7fff39dbdb70 41 64 61 6d Adam
0x7fff39dbdb74 00 7f 00 00 ....
字符串文字"Adam"
存储为char
的数组,从地址0x400ac0开始(位于我系统的.rodata
段中)。
变量name
是指向char
的指针,包含字符串文字的地址(我的系统是little-endian,因此地址读作“向后”) 。
变量name2
是一个char
数组,其内容是从字符串文字复制。
修改
查看生成的机器代码可能会有什么帮助。采取以下计划:
#include <stdio.h>
int main( void )
{
char *name = "Adam";
char name2[] = "Adam";
printf("name = %s, name2 = %s\n", name, name2 );
return 0;
}
我在gcc
的SLES 10系统上编译它,如下所示:
gcc -o name2 -std=c99 -pedantic -Wall -Werror name2.c -Wa,-aldh=name2.lst
在name2.lst中给了我以下汇编程序输出:
GAS LISTING /tmp/ccuuqqGI.s page 1
1 .file "name2.c"
2 .section .rodata
3 .LC0:
4 0000 4164616D .string "Adam"
4 00
5 .LC1:
6 0005 6E616D65 .string "name = %s, name2 = %s\n"
6 203D2025
6 732C206E
6 616D6532
6 203D2025
7 .text
8 .globl main
10 main:
11 .LFB2:
12 0000 55 pushq %rbp
13 .LCFI0:
14 0001 4889E5 movq %rsp, %rbp
15 .LCFI1:
16 0004 4883EC10 subq $16, %rsp
17 .LCFI2:
18 0008 48C745F8 movq $.LC0, -8(%rbp)
18 00000000
19 0010 8B050000 movl .LC0(%rip), %eax
19 0000
20 0016 8945F0 movl %eax, -16(%rbp)
21 0019 0FB60500 movzbl .LC0+4(%rip), %eax
21 000000
22 0020 8845F4 movb %al, -12(%rbp)
23 0023 488D55F0 leaq -16(%rbp), %rdx
24 0027 488B75F8 movq -8(%rbp), %rsi
25 002b BF000000 movl $.LC1, %edi
25 00
26 0030 B8000000 movl $0, %eax
26 00
27 0035 E8000000 call printf
27 00
28 003a B8000000 movl $0, %eax
28 00
29 003f C9 leave
30 0040 C3 ret
31 .LFE2:
如您所见,字符串文字"Adam"
和"name = %s, name2 = %s\n"
存储在.rodata
部分(对于只读数据项)。第18行将字符串文字的地址复制到name
,而第19到22行将字符串文字的内容复制到name2。
答案 1 :(得分:0)
name
和name2
都指向内存中包含相同字符的区域。这是他们彼此唯一的真实关系。
name
是一个指针,它自己只占用sizeof(char*)
个字节。它没有拥有其价值所指向的记忆。由于您已使用字符串文字对其进行初始化,因此其值将是指向包含相同字节序列的位置的指针。该位置通常(但不总是)位于程序中“常量数据”部分的某个位置。可能与函数的机器代码所在的部分相同,但通常是专门用于常量值的部分。
name2
是一个数组,实际上是字符串占用的字节串,而不仅仅是指向它。如果你说
char name2[] = { 'A', 'd', 'a', 'm', '\0' };
它意味着同样的事情,几乎肯定会编译成相同的代码。
存储两个变量的实际值时,几乎完全取决于声明它们的行的位置。如果它们处于一个功能中,两者都将具有“自动存储持续时间”,许多人将其与“堆叠”混淆。另一方面,如果它们不属于任何功能,它们将具有“静态存储持续时间”,并且通常将存在于为全局可变数据保留的程序的一部分中。
name
和name2
之间最大的区别(你应该关心的)是name2
,它是一个数组,是它自己的可变字节序列。除此之外,这意味着您可以安全地修改字符串,只要您不读取或写入数组的末尾。您对name
的指针肯定知道的是它是一个特定的字节值序列。如果您尝试修改这些字节,则调用所谓的“未定义行为”...这意味着程序已经脱轨,并且所有投注都已关闭。 C有权尝试打开虫洞或在您的信用卡上订购十几个比萨饼。 (更有可能的结果是一个段错误。但依赖于这种情况发生,或者发生所有,被广泛认为是一个坏主意。)
答案 2 :(得分:0)
它们都分配在堆栈上。一个是指针,另一个是字符数组。两者都只创建了足够的堆栈空间来保存所提供的字符数,因此您不希望将它们用作用户输入...有一百万种方法可以将用户输入到char *所以我真的不想覆盖它在这里,因为你可以用STL来做,你可以用C做它,你可以用某种GUI来做,你可以从套接字做,你没有指定...查找像cin这样的命令,了解如何将用户控制台输入到char *中,但请记住,在接受输入之前必须分配内存,这就是缓冲漏洞发生的地方。您可能想要研究创建一个大小,然后在 HEAP 上分配您的输入,而不是STACK!
static const int SIZE_USER_NAME = 40;
char *pszUsername = (char*)malloc(SIZE_USER_NAME);
如果你在堆栈上进行分配,那么除非你使用一些较新的“安全”CRT功能,否则你会打开用户输入超过40个字符并丢弃你的堆栈,但是你没有提到任何关于什么的东西这将继续运行等......
希望有帮助...
P.S。完成后不要忘记free(pszUsername);
,否则你也会泄漏内存。
答案 3 :(得分:0)
第一个陈述
char *name = "Adam";
做两件事: 1.为一个未命名的数组分配内存,其中包含ROM中的字符'A','d','a','m','\ 0'(这通常在.text段中;所以数组实际上在代码部分) 2.创建一个名为name的指针,指向未命名的数组。
第二个陈述
char name2[] = "Adam";
在ROM中为“Adam”创建相同的字符串,但也在.data部分(通常是堆栈)中分配大小内存,并在那里复制文字字符串的内容。并创建一个指针name2,它指向数据部分中的位置。
当尝试修改指针指示的内存地址处的值时,差异变得明显:
name[0] = 'a'; //illegal
name2[0] = 'a'; //legal