8

K&R 本の構造に関する章を読んだ後、構造をよりよく理解するためにいくつかのテストを行うことにしたので、次のコードを書きました。

#include <stdio.h>
#include <string.h>

struct test func(char *c);

struct test
{
    int i ;
    int j ;
    char x[20];
};

main(void)
{
    char c[20];
    struct  {int i ; int j ; char x[20];}  a = {5 , 7 , "someString"} , b; 
    c = func("Another string").x;
    printf("%s\n" , c);
}

struct test func(char *c)
{
    struct test temp;
    strcpy(temp.x , c);
    return temp;    
}

私の質問は: なぜc = func("Another string").x;機能しているのですか (違法であることはわかっていますが、なぜ機能しているのでしょうか)? strcpy()最初は(それが最も論理的なことのように思えたので)を使用して書きましたが、このエラーが発生し続けました:

structest.c: In function ‘main’:
structest.c:16:2: error: invalid use of non-lvalue array
4

5 に答える 5

6
    char c[20];
    ...
    c = func("Another string").x;

これは有効な C コードではありません。C89でもC99でもC11でもありません。

明らかに、割り当ての診断なしのモードで最新gccバージョン4.8でコンパイルされます(診断を発行します)。これは、 C89 モードで使用した場合のバグです。-std=c89clanggcc

C90 規格からの関連する引用:

6.2.2.1「変更可能な左辺値は、配列型を持たず、不完全な型を持たず、const 修飾された型を持たない左辺値です。構造体または共用体の場合は、メンバ (. const 修飾された型を持つ、含まれているすべての構造体または共用体の任意のメンバーを再帰的に。"

6.3.16 「代入演算子は、左オペランドとして変更可能な左辺値を持つものとします。」

6.3.16 は制約であり、少なくとも forに発行しないgcc診断を課すため、これはバグです。gcc

于 2013-08-23T21:47:18.383 に答える
0

あなたのコードには2つのエラーがあります:

main(void)
{
        char c[20];
        struct  { int i ; int j ; char x[20];}  a = {5 , 7 , "someString"} , b; 
        c = func("Another string").x;// here of course number one
        printf("%s\n" , c);
}
struct test func(char *c)
{
        struct test temp;
        strcpy(temp.x , c);
        return temp;         // here is number two , when the func finished the memory of function func was freed, temp is freed also. 

}

次のようにコードを記述します。

main(void)
{
        struct test *c;
        struct  { int i ; int j ; char x[20];}  a = {5 , 7 , "someString"} , b; 
        c = func("Another string");
        printf("%s\n" , c->x);
        free(c);                              //free memory
}
struct test * func(char *c)
{
        struct test *temp = malloc(sizeof(struct test));//alloc memory 
        strcpy(temp->x , c);
        return temp;
}
于 2013-08-24T00:05:58.390 に答える
0

OP:しかし、なぜそれが機能しているのですか?どうやら
構造体のフィールドをコピー するときは、型とサイズだけが重要です。 これを裏付けるドキュメントを検索します。

[編集] 割り当てに関する C11 6.3.2 を確認すると、 LValueCは配列であるため、割り当てを格納する場所になるのはその配列のアドレスです (ショックはありません)。関数の結果が式の値であり、サブフィールド参照も式の値であるということです。次に、この奇妙なコードは、式の値(20 バイト) をchar[20] でもある宛先の場所に単純に割り当てるため、許可されます。&c[0]

[Edit2] 要点は、の結果がfunc().x値 (式の値) であり、左側の一致する型 の正当な割り当てであるということです。char[20]一方、右側 (a char[20]) のc = c場合は失敗し、配列全体ではなく配列のアドレスになるため、 に代入できません。これはとても奇妙です。cchar[20]

[Edit3] これは失敗しますgcc -std=c99.

簡単なコードを書いてみました。func関数が構造体を返すことに注意してください。典型的なコーディングでは、大きな不良バイト セット全体のコピーではなく、構造体へのポインターを返すことをお勧めします。

ct = func("1 Another string")うまく見えます。1 つの構造が別の構造にまとめてコピーされました。

ct.x = func("2 Another string").x怪しげに見え始めますが、驚くほど機能します。右半分は問題ないと思いますが、配列への配列の割り当てが間違っているようです。

c = func("3 Another string").x単純に前と同じです。前がよかったなら、これも飛ぶ。興味深いことに、c のサイズが 21 の場合、コンパイルは失敗します。

注:c = ct.xコンパイルに失敗します。

#include <stdio.h>
#include <string.h>

struct test {
    int i;
    char x[20];
};

struct test func(const char *c) {
  struct test temp;
  strcpy(temp.x, c);
  return temp;
}

int main(void) {
  char c[20];
  c[1] = '\0';
  struct test ct;
  ct = func("1 Another string");
  printf("%s\n" , ct.x);
  ct.x = func("2 Another string").x;
  printf("%s\n" , ct.x);
  c = func("3 Another string").x;
  printf("%s\n" , c);
  return 0;
}

1 Another string
2 Another string
3 Another string
于 2013-08-23T22:45:43.010 に答える