-1

我想知道是否存储了 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
4

4 回答 4

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并包含字符串文字地址的指针(我的系统是小端,所以地址读取“向后”)。

该变量name2是一个数组,char其内容是从字符串文字 中复制的。

编辑

可能更有帮助的是查看生成的机器代码。采取以下程序:

#include <stdio.h>

int main( void )
{
  char *name = "Adam";
  char name2[] = "Adam";

  printf("name = %s, name2 = %s\n", name, name2 );
  return 0;
}

我在 SLES 10 系统上编译它,gcc如下所示:

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。

于 2013-11-13T21:17:12.750 回答
0

name并且name2都指向内存中包含相同字符的区域。这是关于他们彼此之间唯一真正的关系。

name是一个指针,只占用自己sizeof(char*)的字节。它不拥有其价值指向的内存。由于您已使用字符串文字对其进行了初始化,因此其值将是指向包含相同字节序列的位置的指针。该位置通常(但不总是)位于程序中“常量数据”部分的某个位置。可能与函数的机器代码所在的部分相同,但通常是专门用于常量值的部分。

name2是一个数组,实际上字符串占用的一堆字节,而不仅仅是指向它。如果你说

char name2[] = { 'A', 'd', 'a', 'm', '\0' };

这意味着同样的事情,并且几乎可以肯定会编译成相同的代码。

两个变量的实际值存储在哪里,几乎完全取决于声明它们的行的位置。如果它们在一个函数中,则两者都将具有“自动存储持续时间”,许多人将其与“在堆栈上”混为一谈。另一方面,如果它们在任何函数之外,它们将具有“静态存储持续时间”,并且通常会存在于为全局、可变数据保留的程序的一部分中。

name和,之间最大的区别(你应该关心的)name2name2,作为一个数组,是它自己的可变字节序列。除此之外,这意味着您可以安全地修改字符串,只要您不读取或写入超出数组末尾的内容。你所知道的关于name's pointee 的唯一信息就是它是一个特定的字节值序列。如果您要尝试修改这些字节,您会调用所谓的“未定义行为”......这意味着程序已经偏离轨道,并且所有的赌注都被取消了。C 有权尝试在您的信用卡上打开一个虫洞或订购一打比萨饼。(更可能的结果是段错误。但依靠这种情况发生,或全部发生,被广泛认为是一个坏主意。)

于 2013-11-13T21:15:28.287 回答
0

它们都分配在堆栈上。一个是指针,另一个是字符数组。两者都只创建足够的堆栈空间来保存提供的字符数,所以你不想将它们用作用户输入......有一百万种方法可以让用户输入到 char* 所以我真的不想涵盖它在这里,因为你可以用 STL 来做,你可以用 C 来做,你可以用某种 GUI 来做,你可以从一个套接字来做,你没有指定...查找命令,如 cin ,要了解如何将用户控制台输入转换为 char *,但请记住,您必须在接受输入之前分配内存,这就是缓冲区利用等事情发生的地方。您可能想考虑创建一个大小,然后在HEAP上分配您的输入,而不是在 STACK 上!

static const int SIZE_USER_NAME    = 40;
char *pszUsername = (char*)malloc(SIZE_USER_NAME);

如果您在堆栈上分配,您会向用户开放自己输入超过 40 个字符并丢弃您的堆栈,除非您使用一些较新的“安全”CRT 函数,但您没有提及任何关于它将运行的内容开之类的……

希望有帮助...

PS 完成后不要忘记free(pszUsername);,否则你也会泄漏内存。

于 2013-11-13T21:16:30.643 回答
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
于 2013-11-13T21:55:52.873 回答