質問

文字列str内の全ての数字を削除する関数
void del_digit(char str[]) を作成。
(例えば、"ab1C9"を受け取ったら、"ABC"にする)
という関数を作りたいのですが、うまくいきません。
過去に似たような『文字列内の数字削除』の質問をされた方が
いましたが、ポインタを使っていました。
http://okwave.jp/qa1775576.html
ポインタを使わずにするには、どうしたらよいのでしょうか?
途中まで作ってみたのですが、うまく動きません。
#include <stdio.h>
#include <ctype.h>

void del_digit(char str[])
{
    unsigned i = 0, j = 0;
    char ctr[] = {'0'};

    while (str[i] != '\0') {
         ctr[i] = str[i];
         i++;
    }
    i = 0;
    while (ctr[i] != '\0') {
         if (ctr[i] < '0' || ctr[i] > '9') {
             str[j] = toupper(ctr[i]);
             j++;
         }
         i++;
    }
    str[j] = '\0';
}

int main(void)
{
    char str[100];

    printf("文字列を入力してください:");
    scanf("%s", str);

    del_digit(str);
    printf("%s\n", str);

    return (0);
}

通報する

回答 (8件)

★追記。
・一時コピーする領域は『buff』を用意しなくても引数『str』に上書きしてもいいですよ。
 今回の場合は文字の削除ですから。→挿入して領域が増加する場合は『buff』などを用意する
 必要があります。
・以上。おわり。

★たくさん回答がありますが、もう一つサンプルを付けます。
・実現方法ですが、引数の『str』から数字部分以外を別領域へコピーする仕組みがメインです。
・そして、別領域にコピーするときに英字の『小文字』を『大文字』に変換する方法も一緒に
 記述すれば良いと思います。
・あと数字文字の判定は『isdigit』関数で行い、小文字ならば大文字に変換するには知っての
 通り『toupper』関数を使います。
・最後に別領域へコピーした内容を引数『str』にコピーしなおせば完成です。

サンプル:
void del_digit( char str[] )
{
 char buff[ 256 ]; ←一時コピーする別領域
 int i; ←コピー先の配列の添え字カウンタ
 int j; ←コピー元の配列の添え字カウンタ
 
 for ( i = j = 0 ; str[j] != '\0' ; j++ ){
  if ( !isdigit(str[j]) ){ ←数字以外を処理
   buff[ i++ ] = (char)toupper( str[j] ); ←大文字変換してコピー
  }
 }
 buff[ i ] = '\0'; ←最後にNULL文字をセット
 strcpy( str, buff ); ←引数 str にコピー
 /*
 for ( i = j = 0 ; buff[j] != '\0' ; i++, j++ ){
  str[ i ] = buff[ j ];
 }
 str[ i ] = '\0'; ←最後にNULL文字をセット
 */
}
最後に:
・上記のサンプルは『del_digit』関数の部分のみです。main 関数は質問者さんのものでいいです。
・また、引数 str の文字列に漢字文字が含まれると文字化けを起します。つまり、漢字非対応です。
・あと『strcpy』の部分を自分でコピーする場合は、『/*』…『*/』の部分になります。
・これで『数字』部分を取り除いて、『小文字』を『大文字』に変換する『del_digit』関数の完成
 です。あまり、難しく考えすぎない方ないいでしょう。→コピーと文字変換を組合わせただけです。
・以上。おわり。

 
 ごめん、訂正。
void del_digit(char *str)
{
int i, j;

for(i = j = 0; str[i] != '\0'; i ++){
if(!isdigit(str[i])){
str[j] = toupper(str[i]);
j ++;
}
}
str[j] = '\0';
return;
}
 

 
 文字列を扱う時点で、"ポインタを使わずに"というのは無理だけど、

#include <stdio.h>
#include <ctype.h>

void del_digit(char *str)
{
int i, j;

for(i = j = 0; str[i] != '\0'; i ++){
str[j] = toupper(str[i]);
j += !isdigit(str[i]);
}
str[j] = '\0';
return;
}

int main(void)
{
char str[] = "a1b2c3d4e5";

puts(str);
del_digit(str);
puts(str);
return 0;
}
 

まずC言語には、『文字列そのもの』という概念はなく、変わりに『1文字を表現するchar型の配列で文字列を表現する』という考え方があります。なので、文字列操作をしようと思うと、文字列を成す各char型の配列を操作しなければなりません。配列の先頭はポインタ変数です。char型の文字列の場合だと、先頭のデータを表現するchar*型の変数だけということになります。通常は、このchar*変数にインクリメントしたりデクリメントしたりして、配列内の要素にchar*変数を移動させて各要素を操作しますが、それがトリッキー見にえて嫌なら、文字列の先頭を指すchar*変数に添え字を付けても配列の各要素を操作することが出来ます。いかがその関数です。適当に書きましたので参考までに。

void hoge(char*str){
int a,s;
//a番目の文字が終端文字'\0'でないならば、
//aを++して繰り返し
for(a=0;str[a];++a){
//a番目の文字が数値ならば
if(str[a]>='0'&&str[a]<='9'){
//数値の削除
for(s=a;str[s];++s) str[s]=str[s+1];
--a;
}
}

return;
}

コードの途中に、途中経過を確認するための
printf関数を適宜入れてみましょう。

ところで、del_digit関数の仕様は
「文字列str内の全ての数字を削除する」だけではないですよね。
「結果をすべて大文字にする」も含んでいてよいのですね?

質問に書かれている方法だと、
 char ctr[] = {'0'};
はサイズ1の配列(ctr[1]と同じ)になってしまいますので
その後のループで配列の範囲外にアクセスしてエラーになります。

なので、配列ctrのサイズは、入力された文字数よりも大きくしないといけません。
とりあえず、512や1024といった数字で試してみてください。

あと、最初のwhileループ内で文字チェックをするように変えれば
2番目のループの回数が減りますよ。
それをさらにステップアップさせたのが、No.1さんの方法ですね。

こちらは 文字列が (結果の文字数)≦(入力文字数) となることを利用していますが、
処理を1ステップずつ紙に書いていけば理解しやすいと思います。

この回答へのお礼

回答ありがとうございました。
配列の範囲を広げたら、おしいところまでいきました!
ただそれだけだと、sacanfでstr[0]に数字を入力すると
文字バケの表示が文字列の最後についてしまったため?
ctr[i] = '\0';
を追加したらうまくいきました。
まだ、おかしいところあるかもしれませんが、大変参考に
なりました。ありがとうございます。

void del_digit(char str[])
{
    unsigned i = 0, j = 0;
    char ctr[1000];

    while (str[i] != '\0') {
         ctr[i] = str[i];
         i++;
    }
    ctr[i] = '\0';
    i = 0;
    while (ctr[i] != '\0') {
         if (ctr[i] < '0' || ctr[i] > '9') {
             str[j] = toupper(ctr[i]);
             j++;
         }
         i++;
    }
    str[j] = '\0';

そのような形にしたいなら、

void del_digit(char str[])
{
unsigned i = 0, j = 0;

while (str[i] != '\0') {
if (str[i] < '0' || str[i] > '9')
{
str[j] = str[i];
j++;
}
i++;
}
str[j] = '\0';
}

みたいにしますけど…(参考まで)

この回答へのお礼

回答ありがとうございました。
処理も少なくてスムーズに、きれいにできました。
ありがとうございます。

このQ&Aは役に立ちましたか?3 件

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

新しく質問する

注目の記事

おしトピへのコメントで10人に1人に500円分のギフト券プレゼント!(先着2000名様)

話題のトピックにさくっとコメントできる「おしトピ」で指定のオーダー3件にコメントした方先着2000名様の10人に1人にギフト券をプレゼント!
フジテレビ出身のフリーアナウンサー長谷川豊氏の質問にも回答受付中!

このQ&Aを見た人が検索しているワード


新しく質問する

このカテゴリの人気Q&Aランキング

毎日見よう!教えて!gooトゥディ

べんりQ&A特集