C基本字符串问题

时间:2013-11-13 21:01:15

标签: c string memory

我想知道是否存储了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 个答案:

答案 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)

namename2都指向内存中包含相同字符的区域。这是他们彼此唯一的真实关系。

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

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

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

它意味着同样的事情,几乎肯定会编译成相同的代码。

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

namename2之间最大的区别(你应该关心的)是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