C言語関係掲示板

過去ログ

No.1180 文字列処理関数を使わずに文字列から文字列を取り出す

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

文字列から文字列を取り出す
投稿者---しん(2004/07/12 01:47:43)


ライブラリ関数と配列を使わないで、任意の文字列の先頭からn番目よりm個の文字列を抜き出してディスプレイに表示するプログラムをつくりたいのですが...教えてくださいお願いします。
例えば abcdefgと入力して、n番目を2、m個を3としたらbcdと表示したいのですが..
#include <stdio.h>
#include <stdlib.h>
char *copy(char *co,char *py)
{
    while(*co++=*py++);
return(0);}
int sub(char *r,char *strat,char *end , char *dummy)
{  char *w;
w=(char*)malloc(50);
dummy=w;
while(*r!=*strat){
    *r++;}
    while(*end-*strat){
    copy(w,r);
    *r++;
    *w++;
    }
    return(0);}
int main(void)
{
char *w;char *str;
char *work;char *p;
char *dummy,*dummy1,*dummy2;

str =(char *)malloc(50);
w=(char *)malloc(50);
p =(char *)malloc(2);
work=(char *)malloc(2);
dummy=str;
while (*str=getchar(),*str!=EOF){
    str++;}*str='\0';
    dummy1=p;
while (*p=getchar(),*p !='\n'){
    p++;}*p=0x00;
    dummy2=work;
while (*work=getchar(),*work !='\n'){
    work++;}*work=0x00;
sub(dummy,dummy1,dummy2,w);
while(putchar(*w),*w!=0x00){
    w++;}
}




No.15440

Re:文字列から文字列を取り出す
投稿者---aki(2004/07/12 02:45:30)


> ライブラリ関数と配列を使わないで、任意の文字列の先頭からn番目よりm個の文字列
> を抜き出してディスプレイに表示するプログラムをつくりたいのですが...教えてくだ
> さいお願いします。例えば abcdefgと入力して、n番目を2、m個を3としたらbcd
> と表示したいのですが..

malloc関数、getchar関数、putchar関数はライブラリ関数ですよ。これらは使ってもいい
んですか?



No.15446

Re:文字列から文字列を取り出す
投稿者---しん(2004/07/12 10:38:07)


malloc関数、getchar関数、putchar関数は使ってもかまいません。strcharとかstrstrといった、文字処理も関数は使わない



No.15447

Re:文字列から文字列を取り出す
投稿者---かずま(2004/07/12 11:33:22)


> 例えば abcdefgと入力して、n番目を2、m個を3としたらbcdと表示したいのですが..
int main(void)
{
    char str[256];  int n, m;

    printf("string: ");
    if (scanf("%s", str) != 1) return 1;
    printf("n: ");
    if (scanf("%d", &n) != 1) return 1;
    printf("m: ");
    if (scanf("%d", &m) != 1) return 1;
    printf("%.*s\n", m, str+n-1);
    return 0;
}

> malloc関数、getchar関数、putchar関数は使ってもかまいません。

printf はよいのですか?



No.15448

Re:文字列から文字列を取り出す
投稿者---かずま(2004/07/12 11:38:37)


> printf はよいのですか?
だめなら、fwrite(str+n-1, 1, m, stdout);


putchar だけを使えというのなら、

void putstr(const char *s, int n) { while (n-- > 0) putchar(*s++); }

を用意して、putstr(str+n-1, m); で呼び出す。



No.15449

Re:文字列から文字列を取り出す
投稿者---円零(2004/07/12 16:30:39)


なんか、scanfも禁止っぽいですよ?
あと、配列も禁止と言ってますね。
尤もmallocがOKなら配列で宣言してポインタ変数に代入すればいいだけのような気もしますが…
まあ良くわからないのでなるべく原形を保ってみる、と…
#include <stdio.h>
#include <stdlib.h>

int crudeatoi(char *s){
    int i = 0;
    while(*s != '\0'){
        i *= 10;
        i += *s++ - '0';
    }
    return i;
}

int sub(char *r, char *strat, char *end, char *dummy){
    int i, length = crudeatoi(end);
    char *w;
    w = dummy;
    r =  r + crudeatoi(strat) - 1;
    for(i = 0; i < length; i++)
        if( (*w++ = *r++) == '\0')break;
    *w = '\0';
    return 0;
}

int main(void){
    char *w, *str, *work, *p, *dummy, *dummy1, *dummy2;
    str = (char *)malloc(50);
    w = (char *)malloc(50);
    p = (char *)malloc(3);     /*2桁まで対応*/
    work = (char *)malloc(3);  /*2桁まで対応*/
    dummy = str;
    while (*str = getchar(), *str != EOF && *str != '\n')str++;
    *str = '\0';
    dummy1 = p;
    while (*p = getchar(), *p != EOF && *p != '\n')p++;
    *p = 0x00;
    dummy2 = work;
    while (*work = getchar(), *work != EOF && *work != '\n')work++;
    *work = 0x00;
    sub(dummy, dummy1, dummy2, w);
    while(putchar(*w), *w != 0x00)w++;
}

って、subの中身が良くわからなかったのでちょっと変えちゃいました。
気付いた問題点は、subに結果を保存するアドレスを渡してるのにも関わらず
わざわざ別のアドレス確保してそこにコピーを行なってる点と、
rとstratを比較している辺り、言ってる仕様と異なってる点、
while(*end-*strat)が無限ループになりそうな点、ですね。
(あと、"strat"って何の略なのかも気になる…)


No.15462

Re:文字列から文字列を取り出す
投稿者---しん(2004/07/12 22:24:32)


円零さん、かずまさんありがとうございます。でもなるべく、ポインタを動かしてやろうと考えているんで、こんな感じに変えてみたんですけど....文字化けしてしまうんです。どう直せばいいか教えてください。わがままですいません。
入力の仕方は
a
b
c
d
e
f
g
^Z


こんな感じに縦にいれる方法に変えてやって見てるんですけど。表示は



見たいに表示させたい。どうかお願いします。
#include <stdio.h>
#include <stdlib.h>
char *copy(char *co,char *py)
{
    while(*co++=*py++);
return(0);}
int sub(char *r,char str,char end , char *dummy)
{  char i;
    char *w;
w=(char*)malloc(50);
dummy=w;
for(i=0;i<=str;i++){
    *r++;}
for(i=0;i<=end;i++){
    copy(w,r);
    *r++;
    *w++;
    }*w=0x00;
    return(0);}
int main(void)
{
char *w;char *str;
char *work;char *p;
char *dummy,*dummy1,*dummy2;

str =(char *)malloc(50);
w=(char *)malloc(50);
p =(char *)malloc(3);
work=(char *)malloc(3);
dummy=str;
while (*str=getchar(),*str!=EOF){
    str++;}*str=0x00;
    dummy1=p;
while (*p=getchar(),*p !='\n'){
    p++;}*p=0x00;
    dummy2=work;
while (*work=getchar(),*work !='\n'){
    work++;}*work=0x00;
sub(dummy,*dummy1,*dummy2,w);
while(putchar(*w),*w!=0x00){
    w++;}*w=0x00;
}



No.15475

Re:文字列から文字列を取り出す
投稿者---円零(2004/07/13 11:19:39)


いや、それは文字化けじゃありません。
化けるどころか、mallocしたときのまんま。生まれたままの姿です。

《くどい解説ここから》→
あなたのプログラムだと、まずmain関数でwに50バイト割り当ててますよね?これを仮に領域Aとしましょう。
次にsub関数を呼び出して、mainのwを"dummy"という仮引数に渡しています。
Cでは引数は必ず値渡しですので、ここで言う「渡す」とは値のコピーにほかなりません。
つまり、領域Aを参照するポインタがこの時点で二つになったということになります。
さてsub関数の中では新たにwというポインタ変数(紛らわしい…)を宣言して、50バイトのメモリブロックを割り当ててます。
これを領域Bと呼ぶことにしましょう。
次いでdummyにwを代入しています。これで領域Bを参照するポインタは二つになりました。
なお当然ながら、mainのwは依然として領域Aへの参照を保っています。
然る後、sun関数内ではsubのwを使って領域Bに対する操作を行なっています。sub関数の内容が正しければコピーが行なわれるでしょう。
ただしあくまで領域Bに対してです。そして残念ながらこのプログラムには領域Bにmain関数からアクセスする手段が見当たりません。
そこを参照しているポインタは二つありますが、どちらもsub関数内のローカル変数ですから。
main関数では最後にmainのwを用いて領域Aの中身を出力してますが、何の意味もないことは明らかでしょう。
←《くどい解説ここまで》

それからsub関数内での処理ですが、なんでchar型のstrやendを当たり前の整数のように扱ってるんですか?
コンソールに「1」って入力しても、変数の値としては例えば49とか入ってるんですよ?
まあ一桁の数であれば、 for(i = '0'; i <= str; i++) とかで処理できないこともないですが…
(おっと、終了条件も「i < str」と直すべきですね)
あと、一文字ごとにenterを押させるのであればgetcharは改行も飲み込んでるので注意。
atoiとか使わないのなら、for(i = '0'; i < end; i++)のループを二回繰り返すのが一番単純な解決策ですかね。


まとめ:
・sub関数の仮引数dummyをwに変え、3〜5行目を削除
・forの初期化式をi = '0'に、条件式の <= を < に修正
・for(i = '0'; i < end; i++)のループを二回繰り返させる
これでとりあえずは動きます。


No.15484

Re:文字列から文字列を取り出す
投稿者---しん(2004/07/13 13:28:44)


ありがとうございます。
>ただしあくまで領域Bに対してです。そして残念ながらこのプログラムには領域Bにmain関数からアクセスする手段が見当たりません。
>そこを参照しているポインタは二つありますが、どちらもsub関数内のローカル変数ですから。

>main関数では最後にmainのwを用いて領域Aの中身を出力してますが、何の意味もないことは明らかでしょう。
>←《くどい解説ここまで》
>
>それからsub関数内での処理ですが、なんでchar型のstrやendを当たり前の整数のように扱ってるんですか?
>コンソールに「1」って入力しても、変数の値としては例えば49とか入ってるんですよ?

この2つが明らかにおかしかったんですね。言われてみると、確かにありえないやり方です。非常に参考になりました。
どうもありがとうございます。