2016-08-17 9 views
1
char *returnString() 
{ 
    return "hello World"; 
} 

int main() 
{ 
    printf("\n %p ", &returnString()); 
    return 0; 
} 

returnString()はこちらになりますか?それは'h'のアドレスを返しますか?
ここにどこが"hello world"(スタック/ヒープ)が格納されていますか?それを見る(印刷する)方法は?でもこの後--->result[0]result[2]strcpy(Hello, "String is Changed");値は変更されませように、第二のプログラムで行う必要がありますどのような変更Cが1つの値(int、charなど)しか返せない場合、文字列リテラル(charの配列)をどのように返しますか?

char Hello[] = "It's Hello"; 

char something[] = "something like "; 

char *readInput(char str[]) { 
    char *tempStr = NULL; 
    if (strcmp(str, "hello") == 0) 
     return Hello; 

    tempStr = (char *)malloc((strlen(something)) + (strlen(str)) + 1); 

    strcpy(tempStr, something); 
    strcat(tempStr, str); 

    return tempStr; 
} 

int main() { 
    int i; 
    char *userInput[] = { "hello", "xyz", "hello", "abc" }; 
    char **result = (char **)malloc(sizeof(char *) * (4)); 

    for (i = 0; i < 4; i++) { 
     result[i] = (char *)malloc(15); 

     result[i] = readInput(userInput[i]); 
    } 
    printf("\n\n"); 

    strcpy(Hello, "String is Changed"); // this should not affect result[0] && result[2] 

    for (i = 0; i < 4; i++) 
     printf("\t\t %s", result[i]); 

    printf("\n"); 
    return 0; 
} 

+0

戻り値の型が文字列リテラルへのポインタである 'のchar *'、です。 – user3386109

+1

文字列リテラルは 'char'の配列で、これを使うと配列の最初の要素へのポインタ、つまり最初の文字へのポインタを取得します。配列は最初の要素へのポインタに減衰するので、2番目のプログラムで 'Hello Hello'を実行するときは' return&Hello [0] 'と同じです。 –

+0

2番目のプログラムではメモリリークがあります。ループ内のメモリを 'main'関数で割り当て、' result [i] 'に代入します。直後に、最初のポインタを失うのと全く同じ 'result [i] 'に再割り当てします。 –

答えて

3

return "hello World";は、char *:文字列リテラル"hello World"の最初の文字へのポインタを返します。この文字列リテラルは、のヌル終端配列として格納されます。これは通常、プログラムの他のconstデータとともにメモリに格納されます。

この配列を変更しようとすると、未定義の動作が発生します。それはconstとみなされ、const char *で処理されます。あなたのprintf文で関数呼び出しの&を使用してはならない、さらに

const char *returnString(void) { 
    return "hello World"; 
} 

としてこの関数を定義する方が安全だろう。読み込みする必要があります。

int main(void) { 
    printf("\n%p\n", (void*)returnString()); 
    return 0; 
} 

をあなたの2番目の質問について、あなたはHelloで文字列のコピーを返す必要があります。

if (strcmp(str, "hello") == 0) 
    return strdup(Hello); 

strdup()はC標準で定義されていませんが、POSIX標準で指定されています。この単純なメソッドを使用します。システムで使用できない場合は、次のように定義できます。

char *strdup(const char *s) { 
    char *p = malloc(strlen(s) + 1); 
    if (p) strcpy(p, s); 
    return p; 
} 
+1

偉大な答え、残念ながらstrdupはC libにありません。 – 2501

+1

詳細:文字列リテラルはヌルとして格納されています。'const'' char'の配列です。文字列リテラルを変更しようとするのはUBですが、 'char *'型で 'const char *'として扱う必要があります。 – chux

+0

@ 2501:正しいですが、 'strdup()'はC標準では定義されていませんが、Posixの一部であるため多くのCライブラリにあります。スタンダードの委員会があいまいな拡張機能に焦点を当て、Posixの機能を標準化できない理由は理解できません。 – chqrlie

3

文字列の配置場所は、書き方によって異なります。これらはすべて文字列を返しますが、異なる方法で返します。

const char *a() 
{ 
    return "hello, world"; 
} 
char *b() 
{ 
    return strdup("hello, world"); 
} 
/* c is wrong */ 
char *c() 
{ 
    char buf[16]; 
    strcpy(buf, "hello, world"); 
    return buf; 
} 
char *d() 
{ 
    static char buf[16]; 
    strcpy(buf, "hello, world"); 
    return buf; 
} 
void e(char *buf) 
{ 
    strcpy(buf, "hello, world"); 
} 

aは文字列リテラルを返します。読み取り専用メモリに格納されており、変更することはできません。

bは、ヒープに割り当てられた文字列を返します。 freeへの呼び出しで解放する必要があります。

cは、スタックに割り当てられた文字列を返します。ただし、ローカル変数(この場合はbuf)へのポインタを返すことができないため、間違っています。閉じ括弧に達すると、参照されているオブジェクトは存在しなくなります。

dは、cを改善しています。変数がstaticと宣言されると、変数は多くのコンパイラで.bssセグメントに格納されます。しかし、それはスレッドセーフではないので、修正ではありません。

eは、リターンメカニズムではなく、アドレスを入力することで文字列を返します。バッファオーバーフローが発生する可能性があるため、このコードはお勧めしません。 eへの引数は、呼び出し側がスタックまたはヒープに割り当てることができます。コピーを実行するのに十分なスペースがある限り、それは機能します。あなたが住所を印刷したい場合は

、printf関数で%pを使用します。

printf("%p", a()); 
+2

'strcpy()'の代わりに) 'static char buf [16] =" hello、world ";' d'を使うことができます。あなたはまた 'void f(char * buffer、size_t buflen){if(buflen> = sizeof(" hello world "))のstrcpy(buffer、" hello world ")を表示する必要があります。 else {assert(buflen> 0);バッファ[0] = '\ 0'; }} '。これは、あなたが主張するバッファオーバーフローの危険性を避け、 'e'を望ましくないものにします。リスクの大きさは、その機能が何をするかによって決まります。ここでは簡単なものでは、リスクは低いです。常に低いとは限りません。 'f'はかなり安全です - 唯一の発行はバッファのヌルポインタまたはバッファ長のゼロサイズに関連しています。 –

+0

もっと正確に言うと、 'a()'はポインタ 'char *'を返します。そのポインタは、文字列リテラルの先頭のアドレスの値を持ちます。 – chux

関連する問題