2017-07-28 6 views
0

私はC言語で非常に新しいです。私はstrcat関数を使用しようとしていました。strcat()関数の使い方は?

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

int main(int argc, const char *argv[]) { 
    char s1[] = "12345"; 
    char s2[] = "abcde"; 

    strcat(s1, s2); 

    puts(s1); 
    puts(s2); 
    return 0; 
} 

この1つは、通常走ったが、

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

int main(int argc, const char *argv[]) { 
    char* s1 = "12345"; 
    char* s2 = "abcde"; 

    strcat(s1, s2); 

    puts(s1); 
    puts(s2); 
    return 0; 
} 

は最後のものが結果を返すことができませんでした。 2つの異なる宣言方法がstrcat関数で異なる結果を返すのはなぜですか?前もって感謝します。

+3

bashの - >男のstrcatの – Jonas

+2

は、あなたはそれが必要とするメモリを割り当てると信じているようです。まあ、そうではありません。 – Siguza

+5

これらはどちらも未定義の動作です。 – BLUEPIXY

答えて

5

Cでは、関数strcatは、連結文字列を含む新しい文字配列を作成しません。新しい文字を格納するのに十分な要素を持っていれば、2番目の文字列の文字を最初の文字配列の最初の文字列に追加します。それ以外の場合、関数は未定義の動作を引き起こす文字配列を越えてメモリを上書きしようとします。

だから、最初のプログラム中の関数の有効な使用は文字の配列は、11個の要素を持つように宣言されたこのプログラムでは、次のよう

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

int main(int argc, const char *argv[]) { 
    char s1[11] = "12345"; 
    char s2[] = "abcde"; 

    strcat(s1, s2); 

    puts(s1); 
    puts(s2); 
    return 0; 
} 

を見ることができます。したがって、追加された文字列"abcde"を収容することができます。

2番目のプログラムでは、ポインタs1が指す文字列リテラルを変更しようとしています。 CおよびC++の文字列リテラルは不変です。文字列リテラルを変更しようとすると、C++の文字列リテラルとは反対のC言語では非定数文字配列の型がありますが、未定義の動作になります。 C標準(6.4.5文字列リテラル)から

7は、それら 要素が適切な値を持って設けられ、これらの配列が異なっているかどうかを指定されていません。 プログラムが にそのような配列を変更しようとすると、動作は未定義です。

したがって、2番目のプログラムでは、十分な要素を持つ文字配列を使用する必要があります。例

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

int main(int argc, const char *argv[]) { 
    char s1[11] = "12345"; 
    char* s2 = "abcde"; 

    strcat(s1, s2); 

    puts(s1); 
    puts(s2); 
    return 0; 
} 

やコンパイラがサポートしているか、動的配列を割り当てる場合は、可変長配列(VLA)のいずれかを使用する可能性があるため。例えば

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

int main(int argc, const char *argv[]) { 
    char *s1 = "12345"; 
    char* s2 = "abcde"; 
    char s3[strlen(s1) + strlen(s2) + 1];  

    strcpy(s3, s1); 
    strcat(s3, s2); 

    puts(s1); 
    puts(s2); 
    puts(s3); 

    return 0; 
} 

それとも

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

int main(int argc, const char *argv[]) { 
    char *s1 = "12345"; 
    char* s2 = "abcde"; 
    char *s3 = malloc(strlen(s1) + strlen(s2) + 1);  

    if (s3 != NULL) 
    { 
     strcpy(s3, s1); 
     strcat(s3, s2); 

     puts(s1); 
     puts(s2); 
     puts(s3); 
    } 

    free(s3); 

    return 0; 
} 
+0

IMO、代替言語ディスカッション(C++)は、この素晴らしいCの答えから、特に "私はC言語で非常に新しい" OPのために、代替言語の議論を削除したり、答えの後半に移すことを提案してください。 – chux

+0

あなたの答えと辛抱強さに感謝します。 – zyx

+0

@zyxまったくありません。どういたしまして。 –

7

両方のコードスニペットは、未定義の動作を呼び出します。最初のスニペットでは、s1は6文字以外の文字を格納するのに十分なスペースがありません。
2番目のスニペットでは、文字列リテラルを変更しようとしています。文字列リテラルを変更しようとすると、未定義の動作につながります。

読むstrcat man page

[...]文字列が重複しないこと、およびdest文字列は結果のために十分なスペースを持っている必要があります。 destのサイズが十分でない場合、プログラムの動作は予測できません。バッファオーバーランは安全なプログラムを攻撃するための好きな手段です

+0

以下は「より良い」ものです:Linux:http://man7.org/linux/man-pages/man3/strcat.3.html、Linux/POSIX:http://man7.org/linux/man-pages /man3/strcat.3p.html、POSIX:http://pubs.opengroup.org/onlinepubs/9699919799/functions/strcat.html、C11-Standard:http://port70.net/~nsz/c/c11/ n1570.html#7.24.3.1この「* linux.die.net *」のスパムは...そうではありませんか? – alk

+2

@alk;それを変更しました。ところで、なぜそれはスパムですか? – haccks

+0

あなたのブラウザは、これらのページが私の机に運ばれている広告をすべて除外しますか? – alk