3
    #include <stdio.h>

    int main()
    {
        char str[3][15] = {"Pointer to","char","program"};
        char (*pt)[15] = str; // statement A
        char *p = (char *)str; // statement B
        printf("%s\n",p[3]); // statement C  - Seg Fault in this line
        printf("%s\n",p); // working properly displaying "Pointer to"
        printf("%s\n",p+1); // here it is pointing to second element of first array so displaying "ointer to"
        printf("%s\n",pt+1); // printing properly "char" as expected
        int num[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
        int (*nm)[3] = num[1];
        int *n = num;
        printf("n - %d\n",n[10]); // statement D
        printf("nm - %d\n",nm[0][0]);
        return 0;
    }

私の質問:

  1. char配列とint配列の場合のデータ格納メカニズムについて明確なアイデアを得るのを手伝ってください

  2. 上記のプログラムでは、ステートメント A に示すように char 配列へのポインターが char の 2D 配列を指している場合、正しく表示されますが、通常の char ポインターによって指され、ステートメント C で char を出力しようとすると、SegFault が発生することを理解しています。代わりに、「n」(最初の配列「ポインターへのポインター」の 3 番目の数字の文字) を出力する必要があるため、int 配列の場合、ステートメント D で適切な要素 n = 11 を取得している理由と、この場合 (ステートメント C) である理由が混乱しています。正しく印刷されません。

  3. char配列の場合のデータの格納方法は、以下に示すこの形式で格納されます


char str[3][15] = {{'P','o','i','n','t','e','r',' ','t','o'},
                   {'c','h','a','r'},
                   {'p','r','o','g','r','a','m'}};

このように格納されている場合、ステートメント D に示されている整数ポインターの配列のように機能するはずです。

4

2 に答える 2

4

コードを段階的に見てみましょう。

char str[3][15] = {"Pointer to","char","program"};

ここでは、15 個の の 3 つの配列からなる配列を作成しましたchar。そして、各char配列を文字列リテラルで初期化しています。リテラルが配列よりも短い場合 - 最後の要素はゼロで埋められるため、次と同じです:

char str[3][15] = {
    {'P', 'o', 'i', 'n', 't', 'e', 'r', ' ', 't', 'o', 0, 0, 0, 0, 0},
    {'c', 'h', 'a', 'r', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {'p', 'r', 'o', 'g', 'r', 'a', 'm', 0, 0, 0, 0, 0, 0, 0, 0}
};

それで

char (*pt)[15] = str; // statement A

ここではpt、 を 15 の配列へのポインタとして作成し、 のcharアドレスで初期化しています。str[0]つまり、からの最初の配列をpt指しています。char[15]str

char *p = (char *)str; // statement B

ダメです。私が見る限り、あなたは最初に占有するメモリpを指すようにしようとしています。式の型は です。つまり、ポインタではなく、文字の配列へのポインタです (このため、キャストを使用する必要があります)。が格納されているセルを実際に指しているという事実に関係なく、それを使用する必要があります。よりタイプセーフな方法で:charstrstrchar (*)[15]charstr'P'

char *p = &str[0][0]; // the same as "p = str[0];"

str[0]が の最初の要素を参照しているstr、つまり の型がstr[0]の 15 個charの配列である場合、最初の要素を参照しcharてアドレス - を取得する&(str[0])[0]か、単に「配列」型の式が型「へのポインタ」に崩壊するという事実を利用できます。最初の配列の要素」、それが機能する理由str[0]です。

先に進みましょう

printf("%s\n",p[3]); // statement C  - Seg Fault in this line

この行は未定義の動作を引き起こします。これは、書式指定子が 2 番目の引数を a にする必要const char *があるのに を渡しているためcharです。1文字を印刷したい場合は、次のようにします。

printf("%c\n", p[3]); // prints "n"

それで

    printf("%s\n",p); // working properly displaying "Pointer to"
    printf("%s\n",p+1); // here it is pointing to second element of first array so displaying "ointer to"

2 番目の引数の型が適切であり、文字列が nul で終了することがわかっているため、これらはうまく機能します。

printf("%s\n",pt+1); // printing properly "char" as expected

率直に言って、 「pt + 1の配列へのポインター」であるため、正しくありませんが、 char「charへのポインター」を渡す必要があります。次のように書き換える必要があります。

printf("%s\n",*(pt+1)); // or pt[1]

ただし、型の非互換性に関係なく、両方のポインターが同じ場所を指しているため、機能しているようです。

についての次のセクションint

int num[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int (*nm)[3] = num[1];
int *n = num;

ここに 2 つの誤りがあります: これらは互換性のない型を持っているため、nmで初期化すべきではありません: "3 つの配列へのポインタ" 対 "4 つの配列/ へのポインタ" (崩壊のおかげ)。また、互換性のない型もあるために初期化できません。あなたが望むものについての私の推測によると、次のように見えるはずです:num[1]intintintnnum

int num[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int (*nm)[4] = num + 1;
int *n = &num[0][0];

そして最後のもの:

printf("n - %d\n",n[10]); // statement D
printf("nm - %d\n",nm[0][0]);

逆参照は正しく、引数も渡されますが、ポインターが正しく初期化されていないことに注意してください。

希望、私はあなたのすべての質問をカバーしました。

于 2016-07-28T08:40:20.900 に答える
2

segfault は、printf に間違った型を渡していることが原因です。

あなたが書いているのは、マトリックスの最初の行のp[3]4番目へのポインターを参照しています。と同じcharstr*(p+3)

3番目の文字を印刷したい場合は、

printf("%c\n",p[3]);

最初の C-String (行列の行 0) を印刷する場合は、次のことを行う必要があります。

printf("%s\n",&p[3]);

%sを望んでいるのでchar *

少なくとも gcc の-Wall場合、コマンドにオプションを追加すると、コンパイラは適切で有用な警告を表示します。

test.c:8:9: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
         printf("%s\n",p[3]); // statement C  - Seg Fault in this line

質問 3 については、正しい保存方法は次のとおりであることに注意する必要があります。

char str[3][15] = {{'P','o','i','n','t','e','r',' ','t','o','\0'},
                   {'c','h','a','r','\0'},
                   {'p','r','o','g','r','a','m','\0'}};

C-String は null で終了するため、たとえば、文字列は文字"Pointer to"を占有します11


最後にintポインターについてです。%dフォーマット指定子はintアドレスではなく値を必要とするため、うまく機能します。だから書く:

printf("n - %d\n",n[10]);

n[10]は、行列の 11 番目の要素num、つまり 3 行目の 3 番目の要素を逆参照しているため、完全に正しいです。と同じ*(n+10)

于 2016-07-28T06:42:50.020 に答える