-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    ....

文字列リテラルは、アドレス 0x400ac0 (私のシステムのセグメントにあります) から始まる"Adam"配列として格納されます。char.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が配列であるため、それ自体が変更可能なバイト シーケンスであることです。とりわけ、これは、配列の末尾を超えて読み書きしない限り、文字列を安全に変更できることを意味します。の pointeeについて確実にわかっていることは、それがバイト値の特定のシーケンスであるということだけです。これらのバイトを変更しようとすると、「未定義の動作」と呼ばれるものが呼び出されます...これは、プログラムがレールから外れたことを意味し、すべての賭けが無効になります。C は、あなたのクレジット カードでワームホールを開こうとしたり、12 枚のピザを注文したりする権利を有します。(より可能性の高い結果は、segfault です。しかし、それが起こることに依存すること、またはすべてが起こることに依存することは、広く悪い考えであると考えられています。)name2name2name

于 2013-11-13T21:15:28.287 に答える
0

それらは両方ともスタックに割り当てられます。1 つはポインタで、もう 1 つは文字の配列です。どちらも、提供された文字数を保持するのに十分なスタックスペースしか作成しないため、それらをユーザー入力として使用したくありません...ユーザー入力を char* に取得する方法は何百万もあるため、実際にはカバーしたくありませんここにあるのは、STL で実行できるため、C で実行でき、何らかの GUI で実行でき、指定していないソケットから実行できるためです... cin などのコマンドを検索してください、ユーザーコンソール入力を char * に取得する方法を見つけるために、ただし、入力を受け入れる前にメモリを割り当てる必要があることを覚えておいてください。サイズの作成を検討してから、入力をSTACK ではなくHEAPに割り当てることをお勧めします。

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

スタックに割り当てると、新しい「安全な」CRT関数を使用していない限り、ユーザーが40文字を超えて入力し、スタックを破棄する可能性がありますが、これが何を実行するかについては何も言及していませんオンなど...

それが役立つことを願っています...

free(pszUsername);PS作業が終わったら忘れないでください。そうしないと、メモリ リークも発生します。

于 2013-11-13T21:16:30.643 に答える