C言語関係掲示板

過去ログ

No.1026 memcpyとstrcpy

[戻る] [ホームページ]
No.13093

memcpyについて
投稿者---mana(2004/03/10 11:54:11)


こんにちは。

たとえば、

char data1[10];
char data2[]="abc";
memcpy( data1 , data2 , sizeof(data1));

とした時に、data2の大きさは4にもかかわらず、その先の値もコピーしようとしていますが、
この時に、メモリの破壊とかは起きないのでしょうか?


No.13094

Re:memcpyについて
投稿者---YuO(2004/03/10 12:06:31)


>とした時に、data2の大きさは4にもかかわらず、その先の値もコピーしようとしていますが、
>この時に、メモリの破壊とかは起きないのでしょうか?

破壊は起きないでしょうけど,アクセス違反でプログラムが止まる可能性はあります。


No.13096

Re:memcpyについて
投稿者---mana(2004/03/10 13:07:01)


素早いご回答ありがとうございます。

> 破壊は起きないでしょうけど,アクセス違反でプログラムが止まる可能性はあります。

ということは、この場合はmemcpyを使わない方がいいということですね。

この場合でも大丈夫な、かわりになる関数とかあるでしょうか?


No.13097

Re:memcpyについて
投稿者---YuO(2004/03/10 13:25:02)


>> 破壊は起きないでしょうけど,アクセス違反でプログラムが止まる可能性はあります。
>ということは、この場合はmemcpyを使わない方がいいということですね。

そうです。


>この場合でも大丈夫な、かわりになる関数とかあるでしょうか?

文字列の複写ですから,strcpyを使うのが普通です。


No.13099

Re:memcpyについて
投稿者---mana(2004/03/10 14:18:36)


ご回答ありがとうございます。

> 文字列の複写ですから,strcpyを使うのが普通です。

説明不足で申し訳ありません。

data1の大きさは固定で、data2が大きさが固定されて無い場合を質問したかったのです・・・。
確かに、strcpyだと、変数の大きさが、data1 > data2の場合は大丈夫だと思いますが、
data1 <= data2の場合、

char data1[10];
char data2[] = "abcdefghijkl"; /*12文字*/
strcpy( data1 , data2 );
printf( "%s\n",data1 );


とすると、printfの結果が、「abcdefghijkl」となるところから、メモリが破壊されている恐れがあると思うのですが・・。



No.13100

Re:memcpyについて
投稿者---YuO(2004/03/10 15:17:19)


>data1の大きさは固定で、data2が大きさが固定されて無い場合を質問したかったのです・・・。
>確かに、strcpyだと、変数の大きさが、data1 > data2の場合は大丈夫だと思いますが、
>data1 <= data2の場合、
(snip)
>とすると、printfの結果が、「abcdefghijkl」となるところから、メモリが破壊されている恐れがあると思うのですが・・。

であれば,strncpyを使うことで対処できます。


No.13102

Re:memcpyについて
投稿者---mana(2004/03/10 16:28:45)


ご回答ありがとうございます。

>であれば,strncpyを使うことで対処できます。

strncpyについて調べてみました。これなら大丈夫そうなので使ってみます。

YuOさん、ありがとうございました。


No.13106

Re:memcpyについて
投稿者---かずま(2004/03/10 20:24:15)


> strncpyについて調べてみました。これなら大丈夫そうなので使ってみます。
strncpy より strncat のほうがよいと思います。

    data1[0] = '\0';  strncat(data1, data2, sizeof(data1)-1);

char data1[1000], data2[] = "abc"; のとき、どうなるかをそれぞれについて
考えてみてください。


No.13109

Re:memcpyについて
投稿者---mana(2004/03/11 10:30:10)


かずまさん、ありがとうございます。

実際に次のソースで試してみました。

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

int main(void)
{
    int i;
    char cpydat[10];        /*strncpy用*/
    char catdat[10];        /*strncat用*/
    
    char moji[]="abc";    /*文字データ*/
    
    cpydat[0] = '\0';
    
    catdat[0] = '\0';
    
    strncpy(cpydat, moji, sizeof(cpydat)-1);
    strncat(catdat, moji , sizeof(catdat)-1);
    
    printf( "strncpy:%s\n",cpydat,sizeof(cpydat)-1 );

    /*cpydatの中身の確認(strncpy 3文字)*/
    for(i=0;i<10;i++){
        printf("%#x ",cpydat[i]);
    }

    printf("\n\n");
    printf( "strncat:%s\n", catdat, sizeof(catdat)-1 );

    /*catdatの中身の確認(strncat 3文字)*/
    for(i=0;i<10;i++){
        printf("%#x ",catdat[i]);
    }

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


実行結果

strncpy:abc
0x61 0x62 0x63 0x0 0x0 0x0 0x0 0x0 0x0 0x0

strncat:abc
0x61 0x62 0x63 0x0 0x0 0xfffffff0 0xfffffffd 0x7f 0xffffffd4 0xffffffcc


となりますね。

strncpyのほうは、コピーする文字列が、指定文字数より
小さい文字列とき、残りのコピーされる側に対し、ヌルを指定文字数まで埋めますが、
strncatのほうは、指定文字数より先にヌルが現れると、そのヌルをセットして終了します。

    char moji[]="abcdefghijkl";    /*文字データ 12文字*/

でやってみても、実行結果が、

strncpy:abcdefghi
0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x0

strncat:abcdefghi
0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x0

になります。

なぜstrncatのほうがよろしいのでしょうか?
私としては、問題なくちゃんとコピーされればよいのですが・・・。

それとも、これは処理系に依存してしまう問題なのでしょうか?


No.13119

Re:memcpyについて
投稿者---かずま(2004/03/12 02:55:57)


> 実際に次のソースで試してみました。

>    char cpydat[10];        /*strncpy用*/

>    cpydat[0] = '\0';

これは不要です。strncpy は、cpydat[0] の値を参照しません。


>    strncpy(cpydat, moji, sizeof(cpydat)-1);

cpydat[9] は、値がセットされません。

    
>   printf( "strncpy:%s\n",cpydat,sizeof(cpydat)-1 );

sizeof(cpydat)-1 は、無意味です。


> strncpyのほうは、コピーする文字列が、指定文字数より
> 小さい文字列とき、残りのコピーされる側に対し、ヌルを指定文字数まで埋めますが、

埋めてほしいのなら、strncpy を使ってください。


>    char moji[]="abcdefghijkl";    /*文字データ 12文字*/
>
> でやってみても、実行結果が、
> 
> strncpy:abcdefghi
> 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x69 0x0

最後の 0x0 は偶然ですね。


> なぜstrncatのほうがよろしいのでしょうか?
> 私としては、問題なくちゃんとコピーされればよいのですが・・・。

strncpy は、
コピーする文字列が指定文字数より小さい場合、余計なことをします。
コピーする文字列が指定文字数より大きい場合、'\0' を付加せず、結果が文字列になりません。


> それとも、これは処理系に依存してしまう問題なのでしょうか?

処理系には依存しません。
 
なお、文字数を制限してコピーすることは、sprintf や sscanf でも出来ます。

void f0(char *s1, const char *s2) { strncpy(s1, s2, 9); }
void f1(char *s1, const char *s2) { strncpy(s1, s2, 9); s1[9] = '\0'; }
void f2(char *s1, const char *s2) { s1[0] = '\0'; strncat(s1, s2, 9); }
void f3(char *s1, const char *s2) { sprintf(s1, "%.9s", s2); }
void f4(char *s1, const char *s2) { sscanf(s2, "%9s", s1); }

void set(char *s) { memset(s, 0x23, 10); }

void dump(const char *s)
{
    int i;
    for (i = 0; i < 10; i++) printf(" %02x", s[i]);
    puts("");
}

int main(void)
{
    char s[10];

    set(s); f0(s, "abc"); dump(s);
    set(s); f1(s, "abc"); dump(s);
    set(s); f2(s, "abc"); dump(s);
    set(s); f3(s, "abc"); dump(s);
    set(s); f4(s, "abc"); dump(s);
    puts("---");
    set(s); f0(s, "abcdefghijklm"); dump(s);
    set(s); f1(s, "abcdefghijklm"); dump(s);
    set(s); f2(s, "abcdefghijklm"); dump(s);
    set(s); f3(s, "abcdefghijklm"); dump(s);
    set(s); f4(s, "abcdefghijklm"); dump(s);

    return 0;
}


No.13120

Re:memcpyについて
投稿者---かずま(2004/03/12 03:29:45)


> なお、文字数を制限してコピーすることは、sprintf や sscanf でも出来ます。

> void f4(char *s1, const char *s2) { sscanf(s2, "%9s", s1); }

と書きましたが、文字列 s2 が空白を含む場合、思ったとおりにコピーできないので、
sscanf は不適切です。


No.13127

Re:memcpyについて
投稿者---mana(2004/03/12 09:39:27)


かずまさん、ソースまで示してくださってありがとうございます。

#私のソースでは、余計なところや足りないところがありましたね・・・。

各関数の特徴がよくわかりました。

strncat、sprintf、sscanfは、確実にヌルを付加するが、
strncpyはそうでない、ということですね。
strncpyを使う時は、最後にヌルを付加するようにするとかしないといけないですね。

しかし、

> strncpy は、
> コピーする文字列が指定文字数より小さい場合、余計なことをします。

「余計なこと」とは、ヌルを埋めてしまうことでしょうか?
なぜ、「余計なこと」なのでしょうか?


No.13130

Re:memcpyについて
投稿者---かずま(2004/03/12 11:03:57)


>「余計なこと」とは、ヌルを埋めてしまうことでしょうか?
>なぜ、「余計なこと」なのでしょうか?

その埋めた多数の '\0' を誰が何のために使うんですか?



No.13131

Re:memcpyについて
投稿者---mana(2004/03/12 11:53:16)


かずまさん、ありがとうございます。

>その埋めた多数の '\0' を誰が何のために使うんですか?

なるほど・・・。
確かに文字列の最後に'\0'がついてさえいれば問題ないですね。

いままで教えていだたいたことを参考にして、プログラムを組んでいこうと思います。

YuOさん、かずまさん、いろいろ教えていただいてありがとうございました。


No.13110

Re:memcpyについて
投稿者---YuO(2004/03/11 12:42:54)


strncpy より strncat のほうがよいと思います。
    data1[0] = '\0';  strncat(data1, data2, sizeof(data1)-1);
char data1[1000], data2[] = "abc"; のとき、どうなるかをそれぞれについて
考えてみてください。


それによってstrncatのほうがよい,というのであれば,単に早すぎる最悪化を行っただけでしょう。
#早すぎたものに「最適化」はあり得ない。

問題にするのであればstrncpyは末尾にナル文字が付加されないことがある,という方であり,
strncpyは書き込まなかった領域をナル文字で埋める,ということではないはずです。


strncpyは複写を行う関数であり,
strncatという連結を行う関数で複写を行うより,
何をやっているかがわかりやすいです。

可読性を低めるようなものは,常に「〜のほうがよい」などと言える物ではなく,
一部の,本当に必要なときにのみ「〜のほうがよい」と言えるのではないでしょうか。