C言語関係掲示板

過去ログ

No673 strcpyの書き換え

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

strcpyの書き換え
投稿者---ライナ(2003/06/19 17:33:31)


こんにちは。
学校の課題で、
「入力した文字列を別の文字型配列にコピーした後、入力した文字列と、コピーした文字列を出力するプログラムを作りなさい。
ただし、2つの文字型配列s,tを引数として、tを指す文字列をsの指す領域にコピーする関数mycpyを作りmain関数ではその関数を呼び出すようにしなさい。」
という要するにstrcpyの書き換えなんですが、


#include<stdio.h>

void mycpy(char *, char *);

int main()
{
    char s[] = {'\0'};
    char t[] = {'\0'};

    printf("文字列を入力して下さい\n");
    scanf("%s", s);

    printf("入力した文字列は %s\nコピーした文字列は %s", s, mycpy(s, t));

    return 0;
}

void mycpy(char *s, char *t)
{
    while(*s != '\0')
      *t = *s;
      ++s;
      ++t;
  
}



として、Cmachineにてコンパイルしたみたところ、
コンパイルは通ったんですが、実行の際に無限ループ(?)に陥ってしまいます。
どこがおかしいのかよくわかりません。
どなたかご指導お願いいたします。

No.7576

Re:strcpyの書き換え
投稿者---none(2003/06/19 17:38:02)


>void mycpy(char *s, char *t)
>{
> while(*s != '\0')
> *t = *s;
> ++s;
> ++t;
>
>}

いくらインデントをそろえても、
while()で実行される文は「*t = *s;」の1文のみです。

while(*s != '\0')
{
    *t = *s;
    ++s;
    ++t;
}


などと書き直すべきでしょう。
ポインタを習ったのなら、「複文」くらいは習いましたよね?

No.7577

Re:strcpyの書き換え
投稿者---ライナ(2003/06/19 17:57:49)


ひええこんなミスをしてたとは。
申し訳ありませんでした。
それで直してみたんですが、そしたら

while(*s != '\0'){

の文で「実行時エラー:24行目 関数呼び出しエラー」と出てまたまた実行できませんでした。
あとはどこがいけないのでしょうか??

No.7578

Re:strcpyの書き換え
投稿者---none(2003/06/19 18:00:37)


直した mycpy() を載せてみ。

No.7580

Re:strcpyの書き換え
投稿者---こん!(2003/06/19 18:08:47)


    char s[] = {'\0'};
    char t[] = {'\0'};
さて、ここには何バイトのエリアが確保されているでしょう?

No.7583

Re:strcpyの書き換え
投稿者---none(2003/06/19 18:32:01)


>char s[] = {'\0'};
>char t[] = {'\0'};
>さて、ここには何バイトのエリアが確保されているでしょう?

それもあったか。
その他にも

>void mycpy(char *, char *);
>printf("入力した文字列は %s\nコピーした文字列は %s", s, mycpy(s, t));

のprintf() の第 3 引数もおかしいな。
void で渡された値から「%s」で書式変換したら何が表示されるのだろうな?

No.7582

Re:strcpyの書き換え
投稿者---ライナ(2003/06/19 18:28:20)


直したmycpy()は、

void mycpy(char *s, char *t)
{

while(*s != '\0'){
*t = *s;
++s;
++t;
}

}


です。

char s[] = {'\0'};
char t[] = {'\0'};

にはええと・・charaだからええと・・1バイト?でしょうか?
??

No.7587

Re:strcpyの書き換え
投稿者---こん!(2003/06/19 18:38:45)


>にはええと・・charaだからええと・・1バイト?でしょうか?
>??

1バイトのエリアにscanf等で文字列を入力出来る?

No.7588

Re:strcpyの書き換え
投稿者---ライナ(2003/06/19 18:48:47)


>1バイトのエリアにscanf等で文字列を入力出来る?

なるほど・・。
ではint型にすればいいのかな・・?

あと、第三引数ってのがよくわかりません。
引数は二個なのでは???


No.7589

Re:strcpyの書き換え
投稿者---こん!(2003/06/19 19:09:03)


>なるほど・・。
>ではint型にすればいいのかな・・?

うぐっ、なんでそうなる〜〜!

ここ ・・・

>あと、第三引数ってのがよくわかりません。
>引数は二個なのでは???

それ以前の問題だったのであえて突っ込まなかったところなのだが。

   printf("入力した文字列は %s\nコピーした文字列は %s", s, mycpy(s, t));

printf()の引数はいくつ有ってそれぞれの意味は?




No.7591

Re:strcpyの書き換え
投稿者---ライナ(2003/06/19 19:23:03)


>うぐっ、なんでそうなる〜〜!
ええっと・・・

char s[] = "\0";
char t[] = "\0";

これでよろしいのでしょうか?

>printf()の引数はいくつ有ってそれぞれの意味は?

引数は「s」と「mycpy(s, t)」の二つで、
「s」は配列、「mycpy(s, t)」は関数ではないのでしょうか??
バカですいません・・・。



No.7593

Re:strcpyの書き換え
投稿者---こん!(2003/06/19 19:45:02)


>char s[] = "\0";
>char t[] = "\0";
>
>これでよろしいのでしょうか?

これは先程示したリンク先をよく読んで理解した上でもう一度直してみてください。

>引数は「s」と「mycpy(s, t)」の二つで、
>「s」は配列、「mycpy(s, t)」は関数ではないのでしょうか??

違います。printf()の引数とお聞きしました。
引数とは()の中に記述しているものです。
   "入力した文字列は %s\nコピーした文字列は %s"
これも引数です。意味はこの文字列を確保しているメモリの先頭アドレスです。

そして

>「s」は配列、

ではなく配列の先頭アドレス、

「mycpy(s, t)」は関数では・・・

関数をわたすとは?確かに記述によってはその関数のコードがロードされている
アドレスをわたす事も出来ないではないでしょうがこの場合はそうではないです
よね。
実際にはこの関数の戻り値を引数として渡しているのです。
ところが渡そうにもこの関数void宣言となっていますので何も返ってきていませ
ん。この場合どういう動作になるのか分かる人は分かるのでしょうけど私はあえ
て追求する気もありません。

では、何をしたいのでしょう?
printfで表示しているメッセージから察するにコピーした結果の文字列を表示し
たいのですよね?では、この第三引数には何を渡せば適当だと思いますか?
つまりはコピーの結果が保持されている先は?

No.7595

Re:strcpyの書き換え
投稿者---ライナ(2003/06/19 20:09:51)


>これは先程示したリンク先をよく読んで理解した上でもう一度直してみてください。

char s[] = "";
char t[] = "";

これでどうでしょう?

さらに

mycpy(s, t);
printf("入力した文字列は %s\nコピーした文字列は %s", s, t);

としてみたんですがどうでしょう?
またバカなことやってるんでしょうか?

これで実行してみたら、実行結果一応出るんですが、
どんな文字列を入力しても
「入力した文字列は aa(文字化け)
 コピーした文字列は a(文字化け)」
と出ます・・・・・・。
うう・・。


No.7597

Re:strcpyの書き換え
投稿者---城後(2003/06/19 20:19:12)


>>これは先程示したリンク先をよく読んで理解した上でもう一度直してみてください。
>
>char s[] = "";
>char t[] = "";
>
>これでどうでしょう?
1バイトしか確保していませんか。
s[0]とt[0]がNULLになっているだけでは。
長い文字列を入れたらフローすると思うのですが。
>
>さらに
>
>mycpy(s, t);
>printf("入力した文字列は %s\nコピーした文字列は %s", s, t);
>
>としてみたんですがどうでしょう?
>またバカなことやってるんでしょうか?
>
>これで実行してみたら、実行結果一応出るんですが、
>どんな文字列を入力しても
>「入力した文字列は aa(文字化け)
> コピーした文字列は a(文字化け)」
>と出ます・・・・・・。
>うう・・。

mycpy関数内で、sとtのアドレスをインクリメントされています。
処理が終わった時点で、アドレスは別の位置売っているのでは
ないですか。
先頭アドレスが返却されていない気がしますが。


No.7601

Re:strcpyの書き換え
投稿者---こん!(2003/06/19 20:30:58)


>mycpy関数内で、sとtのアドレスをインクリメントされています。
>処理が終わった時点で、アドレスは別の位置売っているのでは
>ないですか。
>先頭アドレスが返却されていない気がしますが。

それは無いです。あくまでも渡しているのは配列の先頭アドレスであってポイン
タ変数のアドレスではないですから。

いくら関数の中でアドレスがインクリメントされようとも配列として確保されて
いる領域が移動してしまうわけではありません。あくまでも関数内の静的なポイ
ンタ変数の値が変更されるだけですから。

サイズの問題は別として・・・

No.7602

Re:strcpyの書き換え
投稿者---城後(2003/06/19 20:47:59)


配列の先頭アドレスでした。
いまだに、配列とポインタがごちゃ混ぜになっています。
もう一度、整理をしなくては。

ところで、このにあるソースをそのままコンパイルしたら
printf("入力した文字列は %s\nコピーした文字列は %s", s, mycpy(s, t));
の行がエラーとなりました。
void宣言なのでしかられましたが、
printf("入力した文字列は [ %s ]\nコピーした文字列は [ %s ]\n", s, t);
としたら一応はコンパイルが通りました。

動かしてみたのですが、一応、動きました。
ただ、8文字入れたらオーバフローになりました。
サイズが確保されていないからでしょう。

No.7598

Re:strcpyの書き換え
投稿者---こん!(2003/06/19 20:23:21)


>char s[] = "";
>char t[] = "";

まず、何故ここで初期化をしなければならないのですか?
どうせすぐscanfで入力するのに。

初期化にこだわるくらいならサイズにこだわりましょうよ。

今回の仕様になりますが文字列の長さの制限はいくつなのですか?
当然受け取る領域のサイズもそれ以上確保しないといけないという事はお分かり
ですか?
入れ物が無いと物を受けとることは出来ませんよ。
200ミリリットルのコップに1リットルのジュースは入りませんよ。

>mycpy(s, t);
>printf("入力した文字列は %s\nコピーした文字列は %s", s, t);
>としてみたんですがどうでしょう?

それで意味をちゃんと理解出来ているのであればよろしいです。


No.7608

Re:strcpyの書き換え
投稿者---ライナ(2003/06/20 06:29:27)


すいませんお返事遅れました。

>今回の仕様になりますが文字列の長さの制限はいくつなのですか?

制限は特にありません。

それで、
char s[10];
char t[10];
としてみたら、ちゃんと動いてくれたものの、
10文字以上になるとおかしくなります。
いや、理由はわかるのですが。
そこで、さっきも言ったように制限無いので、
何文字入れても大丈夫ってことにしたいんですが、
それはどうすればいいのでしょうか?
なにとぞご指導をお願いいたします。


No.7609

Re:strcpyの書き換え
投稿者---ともじ(2003/06/20 06:52:57)


おはようございます。

>何文字入れても大丈夫ってことにしたいんですが、
>それはどうすればいいのでしょうか?

何文字入れても大丈夫ってことは、無理なんですよ。
こん!さんが、「200ミリリットルのコップに1リットルのジュースは
入りませんよ。」って言っていますよね。つまり、1リットルのジュース
を入れたいなら、十分な大きさで10リットル分の大きさを用意するとか、
10リットルのジュースを入れたいのなら、100リットル用意するとかしか
ないんです。

ただ、scanfの場合、
 char s[100];
 scanf("%99s", s);
とすると、99文字以上は入らないので、配列を壊す恐れはなくなります。
このとき、文字列は最後に'\0'が付くので、s[100] に対して"%99s"と
指定します。



No.7610

Re:strcpyの書き換え
投稿者---ライナ(2003/06/20 07:38:46)


そうなんですかぁ〜。

ではこれで解決いたしました。
長々とお付き合いいただき、ほんとにありがとうございました。
勉強させていただきました。

No.7616

Re:strcpyの書き換え
投稿者---shelly(2003/06/20 13:34:55)


結局制限がないのなら、動的にとっていくしかないんですよね。

みなさん似たようなことはよくやるんじゃないでしょうか。
ただ1文字ずつ読んでreallocは効率悪い気もします。

書いてみたけど、なんかスマートではない気が。
誰か直して。。

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

char *getline(char **buf, FILE *fp)
{
    char work[1024];
    char *ptr = NULL;
    int size = 1, len = 0;

    *buf = NULL;
    while (fgets(work, sizeof(work), fp)) {
        size += strlen(work);
        if (!(ptr = (char *)realloc(*buf, size))) {
            free(*buf);
            return NULL;
        }
        *buf = ptr;
        strcpy(*buf + len, work);
        len += strlen(work);
        if (work[strlen(work) - 1] == '\n') {
            *(*buf + --len) = '\0';
            break;
        }
    }
    return (*buf);
}


int main(int argc, char* argv[])
{
    char *p = NULL;

    printf( "input string : " );
    if (getline(&p, stdin)) puts(p);
    free(p);

    return 0;
}