2016-07-10 34 views
1
void printInstructions(); 
char *getUserWord(); 


int main() 
{ 
    printInstructions(); 
    char *baseWord = getUserWord(); 
    printf("%s", baseWord); 
    return 0; 
} 


void printInstructions() 
{ 
    printf("      Instructions:      \n" 
    "===================================================================\n" 
    "= This program is a hangman game.         =\n" 
    "= The first user will enter the name to be guessed    =\n" 
    "= After that, the second user will guess the letters of the word =\n" 
    "= the second user will loose if they have three strikes   =\n" 
    "===================================================================\n"); 
    return; 
} 


char *getUserWord() 
{ 
    static char str[20]; 
    scanf("%s", str); 
    return str; 
} 

私の機能getUserWordは、文字列を渡すことによってそのタスクを達成します。私がオンラインで読むものから、メイン関数内の変数に文字列を割り当てる唯一の方法は、char *baseWord = getUserWord();でした。私はこれがなぜ機能しているのかわからないし、これが何がメモリ内で何をしているのかわからない。以下は私にとって意味をなさないものです。なぜこれはうまくいかないでしょうか?文字列を関数に渡します。 C

char baseWord[21]; 
baseWord = getUserWord(); 

答えて

5

あなたは、ポインタと配列が同じものだと信じるという罠に陥ってしまいました。ではない。

文字列は、通常C言語で、charの配列で表され、追加の終端記号'\0'(いわゆるヌル文字)が最後に付加されています。したがって、文字列リテラル"AB"は、'A','B'、および'\0'という値を持つ3つのcharの配列として表されます。

ポインタは配列とはまったく異なり、文字列はcharの配列を使用して表されるため、ポインタと文字列は完全に別個のものです。ポインタは、メモリ内のアドレスを含む変数です。

ここで混乱するのは、配列の名前がいくつかのコンテキストでポインタに変換されていることです。例えば;

char x[] = "AB"; 
char *p = x; 

この割り当ては機能しますが、配列がポインタであること、またはポインタが配列であることを意味するものではありません。代わりに、名前xは、その最初の文字へのポインタに変換されます。だから、初期化は、文字列"AB"の値'A'を持つ文字に

char *p = &x[0]; 

のでpポイントと機能的に同等です。

同じことは、両方のケースで

char *getUserWord() 
{ 
    static char str[20]; 
    scanf("%s", &str[0]); 
    return &str[0]; 
} 

char *getUserWord() 
{ 
    static char str[20]; 
    scanf("%s", str); 
    return str; 
} 

が同等であるので、あなたのコードで起こっている、getUserWord()によって返されたポインタはstr[0]のアドレス値を有します。すなわち、baseWordは現在、配列の最初の文字を指しているので、それが配列であるかのように、それを処理することができるbaseWord

main()
char *baseWord = getUserWord(); 

を初期化するために使用される値です。 Cでは、与えられた値がiの場合、これにはbaseWord[i]main())とstr[i]getUserWord())の間の等価が含まれます。配列の構文が使用されているということは、ポインタと配列が同じものであるということを意味するものではありません。つまり、同じ構文を使用して作業することができます。

しかし、実現するために重要なことは、関数からポインタを返すことができます(また、戻り値は別のポインタに割り当てられた、または初期化に使用された戻り値です)。したがって、main()ではこれは正当なものです。

char *p = getUserWord(); 
p[0] = 'X'; /* will change str[0] in getUserWord() */ 

しかしこれはありません。

char array[20] = getUserWord(); 
+0

ありがとうございます。実際に配列に文字列を渡す方法はありませんか?また、私が "char * getUserWord()"と言うと、それはアドレスを返す関数に伝えますか? –

+0

あなたの最初の質問の文言は不明です。「文字列を配列に渡す」とはどういう意味ですか? 2番目の宣言では、 'char * getUserWord()'はポインタを返す関数を指定し、ポインタはアドレスを含む変数の型です。 – Peter

+0

最初の質問では、実際には関数内に文字列を返すことができます。 –

-1

このコード

char baseWord[21]; 
baseWord = getUserWord(); 

変更可能な左辺値を代入演算子の左のオペランドのために必要とされている間どのアレイから変換されたことは左辺値(N1570 6.3.2.1)ではないため動作しません(N1570 6.5.16)。

calleeから文字列読み取りが格納される配列にポインタを渡すことができます。

#include <stdio.h> 

void getUserWord(char* str); 

int main(void) 
{ 
    char baseWord[21] = ""; /* initialize for avoiding undefined behavior in case no data is read */ 
    getUserWord(baseWord); 
    printf("%s", baseWord); 

    return 0; 
} 

void getUserWord(char* str) 
{ 
    scanf("%s", str); 
} 

この例では省略されていますが、読み取りが成功したかどうかを確認する必要があります。

4

配列はCで代入することはできません。これは、C標準によって義務づけられています。あなたの2番目の例の左辺値はbaseWordで、タイプはchar[21]で、配列です。あなたがタイプstatic char[20]を持ってstrし、戻ったときにあなたの最初の例では

は、それがタイプchar*に変換され、関数から返されたポインタbaseWordに割り当てることができます。 strには静的な記憶期間があるため、ポインタは有効なオブジェクトを指しています。

静的でない文字列を返す場合は、(関数mallocを使用して)それを割り当てたり、既存の文字列を関数に渡したり、文字列を構造体でラップしたりできます。


(より引用:ISO:IEC 9899:201X 6.3.2.1左辺値、配列、および機能指定子1)
変更左辺値は、 が配列型を持っていないことが左辺値でありません不完全な型を持たず、const型を持たず、構造体または共用体の場合は、constを持つ任意のメンバ(再帰的には、 を含み、含まれるすべての集約または共用体の任意のメンバまたは要素を含みません) - 修飾タイプ。

関連する問題