掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板2

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.24896

文字列結合
投稿者---がりんしゃ(2005/12/21 23:49:12)


文字列結合に非常に困っています。

C言語で、関数strchr,memset,memcpyは必ず使用し、
例えば[abcde fghi,,,jkl, ,m]という文字列を区切り文字','以外を結合したいのです。
上記文字列での出力結果は、[abcde fghijkl m]となります。

memcpyは区切り文字と区切り文字の間をコピーするのに使用します。(この意味もわからず・・・)

色々調べたり考えたりましたが、特定の文字を探し出すstrchrと、memcpy,memcpyを使用してどのように結合させればよいのか全く想像がつきません・・・

アドバイスやヒントなど宜しくお願いします。





この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:文字列結合 24899 wiz 2005/12/22 00:38:04
<子記事> Re:文字列結合 24903 とろり 2005/12/22 09:08:06
<子記事> memcpy 24933 がりんしゃ 2005/12/23 16:28:18
<子記事> Re:文字列結合 24942 まきじ 2005/12/23 20:34:03


No.24899

Re:文字列結合
投稿者---wiz(2005/12/22 00:38:04)


>例えば[abcde fghi,,,jkl, ,m]という文字列を区切り文字','以外を結合したいのです。

[abcde fghi,,,jkl, ,m]
これがひとつの文字列ならば結合では無い気がしますが。。。


>memcpyは区切り文字と区切り文字の間をコピーするのに使用します。(この意味もわからず・・・)

memcpy関数は指定されたポインタから指定されたバイト数をコピーする関数です。


>色々調べたり考えたりましたが、特定の文字を探し出すstrchrと、memcpy,memcpyを使用してどのように結合させればよいのか全く想像がつきません・・・

何を調べ、どのように考えたのかを提示したほうがいいと思います。
コレでは『課題の丸投げはしません。』に触れる気がしますし。。。
あと環境(OSとコンパイラ)や症状は具体的に詳しく書いてください



この投稿にコメントする

削除パスワード

No.24903

Re:文字列結合
投稿者---とろり(2005/12/22 09:08:06)


>memcpyは区切り文字と区切り文字の間をコピーするのに使用します。(この意味もわからず・・・)
…,aaaaa,…
という文字列の場合、区切り文字","の間、つまり"aaaaa"のコピーに使うということでしょう。


>色々調べたり考えたりましたが、特定の文字を探し出すstrchrと、memcpy,memcpyを使用してどのように結合させればよいのか全く想像がつきません・・・
>アドバイスやヒントなど宜しくお願いします。

方法はいくつかあると思いますが、パッと思いつくのは以下でしょうか。

1.strchr()で先頭から","を探す。
2.memcpy()で先頭から見つけた","の1つ手前までをコピー
3.strchr()で見つけた","の次から","を探す。
4.memcpy()で前に見つけた","の先から今回見つけた1つ手前までをコピー
5.以降、終端まで3-4を繰返し。

でもこれだとmemset()の出番がないんですよねぇ。
バッファの初期化に使うとか?


この投稿にコメントする

削除パスワード

No.24904

Re:文字列結合
投稿者---がりんしゃ(2005/12/22 09:33:27)


>何を調べ、どのように考えたのかを提示したほうがいいと思います。
>あと環境(OSとコンパイラ)や症状は具体的に詳しく書いてください

申し訳ありません。
関数についてはそれぞれ定義などはわかりましたが、それだけでこれをどのように結合に使用するのかわかりませんでした。
結合に使うならstrtokやstrcatなどの方が使いやすいですし・・・
OSはWindowsXP、開発環境はMicrosoftVisualC++を使ってます。


>1.strchr()で先頭から","を探す。
>2.memcpy()で先頭から見つけた","の1つ手前までをコピー
>3.strchr()で見つけた","の次から","を探す。
>4.memcpy()で前に見つけた","の先から今回見つけた1つ手前までをコピー
>5.以降、終端まで3-4を繰返し。

区切り文字と区切り文字の間のコピーというのはそういうことだったんですね・・・
ありがとうございます。参考にさせていただいて作ってみます。

>でもこれだとmemset()の出番がないんですよねぇ。
>バッファの初期化に使うとか?

うーん・・・問題では文字列が
str[CNT][BUF]={"abcde fds,,,,adsfs"
," sdfa, ,,sdfa,"
,"a df, , sd ,,dfsa"
," , , "};
のように配列で与えられているんですけど、それぞれ列ごとに出力します。
このとき次の列をstrchrとmemcpyで処理する時にmemsetで初期化するのか・・・と考えてみましたが・・・わかりません。




この投稿にコメントする

削除パスワード

No.24905

Re:文字列結合
投稿者---REE(2005/12/22 10:26:43)


最後の終端文字をいれるのにmemsetを使ってみるとか・・
memset(ptr, '\0', 1); // *ptr = '\0' と同じ動作



この投稿にコメントする

削除パスワード

No.24906

Re:文字列結合
投稿者---TJ(2005/12/22 10:47:34)
http://home.f01.itscom.net/toge/programingreport/


>うーん・・・問題では文字列が
>str[CNT][BUF]={"abcde fds,,,,adsfs"
> ," sdfa, ,,sdfa,"
> ,"a df, , sd ,,dfsa"
> ," , , "};
>のように配列で与えられているんですけど、それぞれ列ごとに出力します。
>このとき次の列をstrchrとmemcpyで処理する時にmemsetで初期化するのか・・・と考えてみましたが・・・わかりません。
>

そういう使い方もしくはヌル文字を入れるぐらいしか思いつかないですね。
ただ、動作自体は列ごとに初期化しなくてもよいのですが・・・。
課題ということでしたら関数の使い方を知ろうということなんでしょうね。


この投稿にコメントする

削除パスワード

No.24907

Re:文字列結合
投稿者---RAPT(2005/12/22 11:06:46)


こんなのもアリかな?
# 実際、memset() は不要なんだけどね。
# 普通なら最後に *ptr = '\0'; で済むので。

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

enum{ CNT = 5, BUF = 30 };
int main(void)
{
    char buff[BUF], *ptr = NULL;
    char str[CNT][BUF]={
        "abcde fds,,,,adsfs",
        " sdfa, ,,sdfa,",
        "a df, , sd ,,dfsa",
        "sample",
        " , , ",
    };
    int i, c;

    for( c = 0; c < CNT; ++c ){
        // 元の文字列を出力(確認用)
        printf("  (%s)\n->", str[c]);

        if( strchr(str[c], ',') >= 0 ){
            // カンマが含まれていたら、除外して出力
            memset(buff, 0, BUF);
            ptr = buff;
            for( i = 0; str[c][i] && i < BUF; ++i ){
                if( str[c][i] != ',' ){
                    *ptr++ = str[c][i];
                }
            }
            printf("(%s)\n", buff);
        }else{
            // カンマが含まれていなければ、そのまま出力
            printf("(%s)\n", str[c]);
        }
    }

    return 0;
}



この投稿にコメントする

削除パスワード

No.24913

Re:文字列結合
投稿者---がりんしゃ(2005/12/22 18:18:13)


ありがとうございます。

memsetの使い方はやっぱりそういう使い方なのかな・・・

あとはmemcpyを使って区切り文字と区切り文字の間をコピー(文字の結合?)をしなければならないので、RAPTさんのソースを参考にさせていただいて頑張ってみます・・・

カンマが含まれていたら除外して出力する部分をmemcpyに応用すれば良いですよね?

    memset(buff, 0, BUF);
    ptr = buff;
    for( i = 0; str[c][i] && i < BUF; ++i ){
       if( str[c][i] != ',' ){
        *ptr++ = str[c][i];
       }
    }


ソースのこの部分(特に*ptr++ = str[c][i])はどういう処理なのでしょうか?



この投稿にコメントする

削除パスワード

No.24915

Re:文字列結合
投稿者---RAPT(2005/12/22 18:40:47)


ポインタを使わず、すべて配列の添え字でアクセスするなら、
下記のようになります。(上記コードから抜粋)

int i, c, p;
for( c = 0; c < CNT; ++c ){
    // 元の文字列を出力(確認用)
    printf("  (%s)\n->", str[c]);

    if( strchr(str[c], ',') >= 0 ){
        // カンマが含まれていたら、除外して出力
        memset(buff, 0, BUF);
        p = 0;
        for( i = 0; str[c][i] && i < BUF; ++i ){
            if( str[c][i] != ',' ){
                buff[p] = str[c][i];
                ++p;
            }
        }

それから、strchr() を使うために、わざわざ下記のように
していますが、これも、本来は不要。
> if( strchr(str[c], ',') >= 0 ){


参考までに、指定関数を使わないで処理すると下記のようになります。
memset()もmemcpy()もstrchr()もポインタも使っていない。。

#include <stdio.h>

enum{ BUF = 30 };
int main(void)
{
    char buff[BUF], str[][BUF]={
        "abcde fds,,,,adsfs",
        " sdfa, ,,sdfa,",
        "a df, , sd ,,dfsa",
        "sample",
        " , , ",
    };
    int i, c, p, CNT = sizeof(str)/sizeof(str[0]);
    for( c = 0; c < CNT; ++c ){
        printf("  (%s)\n->", str[c]);
        for( i = p = 0; str[c][i] && i < BUF; ++i ){
            if( str[c][i] != ',' ){
                buff[p] = str[c][i], ++p;
            }
        }
        buff[p] = '\0';
        printf("(%s)\n", buff);
    }

    return 0;
}



この投稿にコメントする

削除パスワード

No.24922

Re:文字列結合
投稿者---shu(2005/12/22 20:39:46)


> 参考までに、指定関数を使わないで処理すると下記のようになります。
> memset()もmemcpy()もstrchr()もポインタも使っていない。。

//
//  出力結果のみを求めたプログラム
//

//
#include <stdio.h>

//
//
int main( void )
{
    char *str[] = {
        "abcde fds,,,,adsfs",
        " sdfa, ,,sdfa,",
        "a df, , sd ,,dfsa",
        "sample",
        " , , ",
        NULL
    }, **pp, *p;
    
    //  普通に表示
    for (pp = str; *pp; pp++)
    {
        puts( *pp );
    }
    
    //
    for (pp = str; *pp; pp++)
    {
        //  puts( *pp )の改変部
        for (p = *pp; *p; p++)
        {
            if (*p == ',')
                continue;
            
            putchar( *p );
        }
        putchar( '\n' );
    }
    
    return 0;
}



この投稿にコメントする

削除パスワード

No.24923

Re:文字列結合
投稿者---shu(2005/12/22 20:51:25)


>> 参考までに、指定関数を使わないで処理すると下記のようになります。
>> memset()もmemcpy()もstrchr()もポインタも使っていない。。

……ポインタは使いました。


この投稿にコメントする

削除パスワード

No.24924

Re:文字列結合
投稿者---RAPT(2005/12/22 21:53:38)


>>> 参考までに、指定関数を使わないで処理すると下記のようになります。
>>> memset()もmemcpy()もstrchr()もポインタも使っていない。。
>
>……ポインタは使いました。

うん、正しくは使っているけど。
混乱するかなと思ってあえて言ってみた。

突っ込まれたので、ポインタ型の自動変数は使っていない、に改めます。


この投稿にコメントする

削除パスワード

No.24925

Re:文字列結合
投稿者---がりんしゃ(2005/12/22 22:37:30)


色々と参考になるソースをありがとうございます。
初めは文字列処理がほとんどわかりませんでしたが大分理解できるようになってきました。

ただ未だmemcpyをどのように活用したら良いのかわかりません。。。

例えば、
    char data1[30] = "abc edf ghi jkl m";
    char data2[30] = "nop qrs tuv w xyz";
    memcpy(data1+5,data2+9,3);
    printf("%s",data1);
    出力結果 → abc tuv ghi jkl m
のように使えますよね?これをどのように活用したら良いものか・・・


この投稿にコメントする

削除パスワード

No.24926

Re:文字列結合
投稿者---shu(2005/12/22 22:55:52)


>>……ポインタは使いました。

は、自分(shu)のプログラムに対しての追記になります。

……編集機能が欲しい。


この投稿にコメントする

削除パスワード

No.24971

Re:文字列結合
投稿者---かずま(2005/12/24 22:31:15)


>       if( strchr(str[c], ',') >= 0 ){

ポインタの大小比較は、2つのポインタが同じ配列の要素を指している場合
しか出来ないことになっています。
0 は NULL ですから、等値比較だけが許されます。
この場合、ほとんどの処理系では、多分 else には行かないでしょう。



この投稿にコメントする

削除パスワード

No.24933

memcpy
投稿者---がりんしゃ(2005/12/23 16:28:18)


色々とアドバイスありがとうございます。
strchrについては多少理解できましたが、未だmemcpyで苦戦しています。。

//------------------------------------------------------

  char data[BUF] = "abc  def,,,,,ghi";
  char new_data[BUF];
  char findchr = ',';
  char *stop;

  stop = strchr(data,findchr);//dataから','を探す ・・・(ア)

  memcpy(new_dataに、dataの先頭から(ア)で見つけた','の1つ前までをコピー); //・・・(イ)

  strchr(次の','を探す); //・・・(ウ)
  if(','が見つかれば)
    memcpy(1つ前の','と、見つけた','の間の文字列を(イ)のnew_dataの後ろにコピー);
  //(ウ)以降を配列の最後まで繰り返す(forかwhileか・・・)


//--------------------------------------------------

このようなアルゴリズムで考えていますが、(イ)のmemcpyの処理がどのようにすればいいのか苦戦しています。

アドバイスお願いします。。



この投稿にコメントする

削除パスワード

No.24941

Re:memcpy
投稿者---TJ(2005/12/23 20:09:25)
http://home.f01.itscom.net/toge/programingreport/


  char str1[] = "abc ,eerfsc , , ,b b ";
  char str2[256];
  char *p1, *p2, *p3;

  p1 = str1;
  p2 = str2;

  while((p3 = strchr(p1, ',')) != NULL){
    memcpy(p2, p1, p3-p1);
    p2 += p3-p1;
    p1 = p3+1;
  }

  strcpy(p2, p1);
  printf(str2);



こんな感じでどうでしょう。 最後にstrcpy使っていますけど、strlenとか使えばmemcpyだけでもできますね。


この投稿にコメントする

削除パスワード

No.24943

Re:memcpy
投稿者---shu(2005/12/23 20:47:23)


>
アドバイスお願いします。。


以前、がりんしゃさんが質問されていたスレッド(マスク処理についてのもの)で、
最終的に感じたのは、ほんのちょっとした言葉の食い違いによる相互誤解。

で、今回のがりんしゃさんの質問を読み直し、

>C言語で、関数strchr,memset,memcpyは必ず使用し、

というところに注目してみました。

これらの関数は、必ず1度に使わなければならないのでしょうか?
それぞれのプログラムを使った3パターンのプログラムを作るのでは駄目なのか?

無理に3つ一度に使おうとすると、気持ちの悪いプログラムにしかならない気がしますが、
1つづつなら、それなりに納得のいくプログラムにもなるだろうし、
関数の使い方も覚えられるだろうし、問題として納得がいく。

……ついで
3パターンのプログラムを作っていいですか?なんて出題者には聞かないで下さい。


この投稿にコメントする

削除パスワード

No.24942

Re:文字列結合
投稿者---まきじ(2005/12/23 20:34:03)


/*
compiler : gcc 3.4.2 (mingw-special)
option : -std=iso9899:1999 -pedantic -O2 -Wall
*/

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

enum{N=256};

int main(void){

    static char buf[] = "abc,def,,ghi,,,jkl";
    char sep = ',';
    char str[N];
    char *s = buf, *e, *p = str;
    
    memset(str,'\0',N);
    
    while(*s){
        e = strchr(s,sep);
        if(!e) e = &buf[strlen(buf)];
        memcpy(p,s,e - s);
        p += (e - s);
        for(s = e; *s != '\0' && *s == sep; s++);
    }
    
    puts(buf);
    puts(str);
}



この投稿にコメントする

削除パスワード

No.24954

Re:文字列結合
投稿者---がりんしゃ(2005/12/24 00:21:27)


TJさん、まきじさんありがとうございます。

コピーする文字列の先頭のポインタと、検索した文字のポインタの差分コピーすればいいんですね。
ありがとうございました。

かなり余談ですが、TJさんのページの画像処理に関して書いている部分、今私がやっている卒業研究に関連していることが書かれていてかなり為になりました。

shuさん、
>>C言語で、関数strchr,memset,memcpyは必ず使用し、
>というところに注目してみました。
>
>これらの関数は、必ず1度に使わなければならないのでしょうか?
>それぞれのプログラムを使った3パターンのプログラムを作るのでは駄目なのか?

これについては、絶対そうだとは正直言い切れません・・・が、
これと別の問題ですが似たような問題で、strtokとstrcatを必ず使用して・・・という問題があったのですが、そちらはそれほど苦労も無く作ることができました。それでは両方同時に使用して作成したので、今回の問題も同じ(3つ同時に使用)だと解釈してやっておりました。


今回の問題をやっていて思ったのは、処理は同じなのに別の関数を使ってわざわざ面倒くさいことをしなくても・・・と思ったのですが、誰かにも指摘されましたが、おそらく(というかほぼ絶対)関数の使い方を理解するということだと思うので。。。


今回使った関数についてはある程度理解できました。
ポインタの使い方が未だに上手くできませんが。。。
ありがとうございました。


この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧