文字列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);
}

このQ&Aに関連する最新のQ&A

A 回答 (8件)

★追記。


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

★たくさん回答がありますが、もう一つサンプルを付けます。


・実現方法ですが、引数の『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』関数の完成
 です。あまり、難しく考えすぎない方ないいでしょう。→コピーと文字変換を組合わせただけです。
・以上。おわり。
    • good
    • 0

 


 ごめん、訂正。
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;
}
 
    • good
    • 1

 


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

#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;
}
 
    • good
    • 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;
}
    • good
    • 0

コードの途中に、途中経過を確認するための


printf関数を適宜入れてみましょう。

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

質問に書かれている方法だと、


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

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

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

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

回答ありがとうございました。
配列の範囲を広げたら、おしいところまでいきました!
ただそれだけだと、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';

お礼日時:2007/02/16 12:13

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



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';
}

みたいにしますけど…(参考まで)
    • good
    • 0
この回答へのお礼

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

お礼日時:2007/02/16 12:04

このQ&Aに関連する人気のQ&A

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

このQ&Aを見た人はこんなQ&Aも見ています

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

このQ&Aと関連する良く見られている質問

Q指定した文字を削除したい

こんにちは。質問をさせてください。

---------------------------------------------------------------
address = "ここ$http://www.aaaaa.co.jp$moji=dddd$";
---------------------------------------------------------------
変数addressに格納された文字列で、
"http://"の1文字前に"$"があった場合は、
"$"を削除したいのですが、どのようにすれば
いいでしょうか?
※http://の前の"$"以外はそのまま残します。

Aベストアンサー

#include <iostream>
#include <string>

int main() {
std::string address = "ここ$http://www.aaaaa.co.jp$moji=dddd$";
std::string::size_type pos = address.find("$http://");
if ( pos != std::string::npos ) {
address.erase(pos,1);
}
std::cout << address << std::endl;
return 0;
}

QC言語 数字を削除する関数

#include <stdio.h>

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

while (str[i]) {
if(str[i] >= '0' && str[i] <= '9') {
count++;
}
else {
str[i - count] = str[i];
}
i++;
}
str[i - count] = '\0';
}

str内の全ての数字を削除する関数です。

AB1C9と入力するとABCと表示されます。

まずwhile (str[i])のとこのiは5までいくと思います。

5まで行った時にstr[5]は\0だからelseのほうに行ってstr[5- 2] = str[5];という風に処理されると思います。

その段階でstr[3]には¥0が入っていると思うのですが最後に
str[5- 2] = '\0';でまたstr[3]に\0を入れる処理をしているのはなぜなんでしょうか?

最後のstr[i - count] = '\0';を消して実行してみると
「ABCC9」と表示されてしまいます。

教えてくださいm(_ _ )m

#include <stdio.h>

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

while (str[i]) {
if(str[i] >= '0' && str[i] <= '9') {
count++;
}
else {
str[i - count] = str[i];
}
i++;
}
str[i - count] = '\0';
}

str内の全ての数字を削除する関数です。

AB1C9と入力するとABCと表示されます。

まずwhile (str[i])のとこのiは5までいくと思います。

5まで行った時にstr[5]は\0だからelseのほうに行ってstr[...続きを読む

Aベストアンサー

>5まで行った時にstr[5]は\0だからelseのほうに行って

これは正しくないのではないでしょうか。
str[5]は'\0'だから、ifもelseも通らずに、while文のループを抜けると思います。

Q文字列strの中から文字cを探すプログラム(C言語)がわからない

文字列strの中から文字cを探すプログラム(C言語)がわからない
柴田望洋さんの「[新版]明解C言語」という本の演習11-2なんですがどうしてもわかりません。間違いは無いと思うのにコンパイルすると警告を吐かれます。

僕が書いたプログラムを載せます。

/*
文字列strの中に、文字cが含まれていれば(複数ある場合は、最も先頭側とする)、
その文字へのポインタを返し、含まれていなければNULLを返す関数
char *str_chr(const char *str, int c) {}
を作成せよ。
*/
#include<stdio.h>
char *str_chr(const char *str, int c){
while(*str){
if(*str==c) return str;
str++;
}
    return NULL;
}
int main(){
char *str;
char c;

scanf("%s",str);
scanf(" %c",c);
    printf("%d",str_chr(str,c));

return 0;
}

コンパイラは「関数str_chrのif分の中のreturn strの型変換に問題がある」と言っているんです。
型変換はしるつもりは無いのにコンパイラはなぜそのように認識するのでしょうか。
またネット答えを探しましたがどうやらこのreturn strの部分はreturn (char*)strが正解のようです。意味がわかりません。strはポインタなのになぜまたわざわざchar型に変換しているのですか?といか(char*)の意味が根本的にわかりません。

質問ばかりですみません。初心者でポインタがどうにも理解できないんです。
誰か詳しい人教えてください。
お願いします。

文字列strの中から文字cを探すプログラム(C言語)がわからない
柴田望洋さんの「[新版]明解C言語」という本の演習11-2なんですがどうしてもわかりません。間違いは無いと思うのにコンパイルすると警告を吐かれます。

僕が書いたプログラムを載せます。

/*
文字列strの中に、文字cが含まれていれば(複数ある場合は、最も先頭側とする)、
その文字へのポインタを返し、含まれていなければNULLを返す関数
char *str_chr(const char *str, int c) {}
を作成せよ。
*/
#include<stdio.h>
char *str_chr(const ch...続きを読む

Aベストアンサー

char *str_chr(const char *str, int c) {}

という宣言では
戻り値: char *型(charへのポインタ)
引数: str (cosnt char *型/const charへのポインタ)
となります。

const char というのは、「変更できないchar」と言う意味です。
char c='A' ;
const char cc='A' ; /* 初期化によってのみ代入可能 */

c ='C' ; /* OK */
cc ='C' ; /* エラー */

const char * はconst char への(普通の)ポインタです。ポインタが指す実体はconst charなので変更できませんが、ポインタ自身は通常の変数なので変更できます。
char str[] = "abcde" ;
char * cp = str;
const char* ccp ="ABCDE" ;

cp ++ ; /* OK */
*cp = 'A' ; /* OK */

ccp ++ ; /* OK */
*ccp = 'A' ; /* エラー */

このように、振舞いが違うので、char/char *型とは別の型として扱われます。
char → const char,char * → const char * は暗黙の型変換ができます。変更を禁止するだけですから。
逆方向は、(本来は)基本できません。const の意味を失ってしまうし、文字列リテラルのような本当に変更してはいけない(致命的なエラーになりかねない)ものもあるからです。

型変換(キャスト)は、暗黙の変換ができない場合でも、強制的に型変換を行うもので、変換したいものの前に
(変換したい型)
と付けます。 (char *)str はstrの型を強制的にchar *型にします。
なお、この変換は、キャストを書いた箇所だけのもので、変数そのものを変換するわけではありません。


さて、問題のプログラムですが。
return str としていますから、char * 型をreturnしなければならないところに、const char *型を指定している、という警告です。
const char * → char *の暗黙の型変換は無いので、char *として使えない、ということです。
そのため、戻り値の型を合わせるために(char *)でキャストしています。


> strはポインタなのになぜまたわざわざchar型に変換しているのですか?

char型には変換していません。
char型に変換するときは(char)です。

char *str_chr(const char *str, int c) {}

という宣言では
戻り値: char *型(charへのポインタ)
引数: str (cosnt char *型/const charへのポインタ)
となります。

const char というのは、「変更できないchar」と言う意味です。
char c='A' ;
const char cc='A' ; /* 初期化によってのみ代入可能 */

c ='C' ; /* OK */
cc ='C' ; /* エラー */

const char * はconst char への(普通の)ポインタです。ポインタが指す実体はconst charなので変更できませんが、ポインタ自身は通常の変数なので変更できます。
c...続きを読む

Qfgetsで拾われる改行文字を削除したい

お世話になります

 C言語初心者のものです。今課題でC言語を用いたプログラミングを
Fedora上でやっています。問題は、fgetsでテキストファイルから、取得
した文字列の中から改行文字を削除できないことです。文字変数のアド
レスはわかっているのですが、終端文字に置換しようとすると、セグメ
ントエラーになってしまいます。これは如何にして解決すべきでしょう
か。よろしくお願いします。

Aベストアンサー

ポインタとかアドレスとか、C言語の用語としてあるものを別の意味に使うとまぎらわしいです。

「ポインタ」「アドレス」と言われたら、 この例なら str, str+i が思い浮びます。
「文字変数のアドレス」だと
char c ;
に対しての
&c
が思い浮びます。

配列なら「添字」、意味的には「x文字目」ですね。

> for(i=0;;i++){
> if(*(str+i)=='/n') {
> *(str+i)='\0';
> break;
> }
> }
/nが\nの間違いなら、この方法で半分正解です。もう少し広い範囲(可能なら全体)で見ないことにはなんとも言えません。
fgetsが最大文字数に達したり、ファイルの最後になったりで、strに改行文字が含まれない場合には、このループは止まりません(Segmentension Falutになって止まる)

・そのような状態になってないか、予めチェックする
・ループを終了させる仕組みを用意しておく
: forの終了条件を記述する、for中で if(*(str+i)=='\0') { break;} 等としておく、等
といった対策が必要です。


あと細かいところを言えば
・strを配列で用意したなら *(s+i)じゃなくてs[i]でいいんじゃないかな
・あるいは char *pみたいにしておいて、 iのループでなく pでループを組む( for(p=str;*p!='\0';p++) )とか。

ポインタとかアドレスとか、C言語の用語としてあるものを別の意味に使うとまぎらわしいです。

「ポインタ」「アドレス」と言われたら、 この例なら str, str+i が思い浮びます。
「文字変数のアドレス」だと
char c ;
に対しての
&c
が思い浮びます。

配列なら「添字」、意味的には「x文字目」ですね。

> for(i=0;;i++){
> if(*(str+i)=='/n') {
> *(str+i)='\0';
> break;
> }
> }
/nが\nの間違いなら、この方法で半分正解です。もう少し広い範囲(可能なら全体)で見ないことにはなんとも言えません。
fgetsが...続きを読む

QExcel 文字列の中から数字だけを削除したい

Excel 2007で各セルに文字列として入力されている、数字を削除し文字だけにしたい。
数字は先頭に入力されています。(顧客コード)

例:
12345-001 ABC株式会社
98765- ZYX有限会社ごお商会 等

数字を削除し文字列だけで元のセルにセットしたいです。


きっと簡単なことなんでしょうけど、過去を検索しても良くわかりませんでした。

よろしくお願いいたします。

Aベストアンサー

[No.3お礼]へのコメント、

私が提示した式の意味が分かる(と思う)添付図を参照ください。
B1: =TRIM(ASC(A1))
C1: =FIND(" ",B1)
D1: =MID(B1,C1+1,99)

最後の式中の B1、C1 に上2つの式を代入すれば、提示式になります。

セル A2 の「ZYX有限…」の直前は全角スペースだったので、半角スペース1個にするために、先ずはASC関数で全角スペース1個を半角スペース2個にし、TRIM関数で複数個の半角スペースを1個に置き換えています。ちなみに、文字列の左端や右端にスペースがあればそれらを除去します。
最初のスペースの「次」から文字列を切り出すので「+1」になっています。
A列の文字数は百文字以上は考えなくてよかろうと推測して「99」にしました。

【注意】3行目以降に示したように、全角アルファベットおよび全角カナは、何れも半角文字になってしまいます。

以上の解説で分からなければ、貴方の「レベル」に合った回答に従ってください。

Qint型からchar型への変換

タイトル通り、int型からchar型への変換の仕方がわかりません!><
どうしたらいいのでしょうか?

Aベストアンサー

#include <stdio.h>


char buf[5];
int no;

no = 10;
sprintf(buf, "%d", no);

Q文字列中に含まれる文字の個数をカウントするプログラムについて…

文字列、1文字が与えられたとき、これをポインタで入力し文字列中に含まれる文字の個数を計算するプログラムを作成せよ。

と、いう課題がだされたんですけど、ユーザが任意の文字列と1文字を入力できるようにすることができません…。
多分main関数の部分をちょっといじくればよいと思うのですが…。
どなたかアドバイスをお願いします。
#include <stdio.h>

int count(const char *str, const char ch)
{
int cnt=0;
while (*str!='\0')
{
if (*str==ch)
cnt++;
str++;
}
return cnt;
}

int main()
{
const char *str="hello,world!";
const ch='o';

int cnt;

cnt=count(str, ch);

printf("%s中に%cは%d個です\n", str, ch, cnt);


return 0;
}

文字列、1文字が与えられたとき、これをポインタで入力し文字列中に含まれる文字の個数を計算するプログラムを作成せよ。

と、いう課題がだされたんですけど、ユーザが任意の文字列と1文字を入力できるようにすることができません…。
多分main関数の部分をちょっといじくればよいと思うのですが…。
どなたかアドバイスをお願いします。
#include <stdio.h>

int count(const char *str, const char ch)
{
int cnt=0;
while (*str!='\0')
{
if (*str==ch)
...続きを読む

Aベストアンサー

scanf"%s", str)は、バッファオーバーフローの危険と改行文字の食べ残し問題がありますね。
-- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< --
int main()
{
char ch;
char str[BUFSIZ];
int cnt;

printf("文字列を入力して下さい > ");
fgets(str,BUFSIZ,stdin);

printf("カウントする文字を入力してください > ");
ch = getchar();

cnt=count(str, ch);
printf("%s中に%cは%d個です\n", str, ch, cnt);

return 0;
}

Qテキストファイルの文字列の削除

1行あたりIPアドレスが1つ書いてあるテキストファイルから、指定したIPアドレスを削除するプログラムを作成しています。

r+モードでfoepnした後にfgetsで一行ずつ読み取り、指定されたIPアドレスかどうかをチェックし、該当すればその行をNULLで埋め尽くしているのですが、サクラエディタなどで開くとその行が削除ではなくNULL文字で埋め尽くされているといった現象になります。
削除するにはどうすればよいでしょうか?

ipaddress.txt
---------------------
192.168.0.1(\n)
192.168.0.2(\n)
192.168.0.3(\n)
---------------------

以下、コード
bool DeleteAllowIP(char *ipaddr)
{
  FILE*fp;
  charszBuf[256];
  intleng = 0;
  longposi=0;

  // 初期化
  FillMemory(szBuf, sizeof(szBuf), 0);

  // ファイルオープン(追記)
  if(fopen_s(&fp, AllowPath, "r+"))
    return FALSE;
  // 削除
  while (NULL != fgets(szBuf, sizeof(szBuf), fp)){  // 1行読み取る
    if(NULL != (strstr(szBuf, ipaddr))){  // 削除IPに合致するIPを検索
      fseek(fp, posi+1, SEEK_SET);  // 削除する先頭行セット
      leng = strlen(szBuf) - 1;  // 改行を除く文字数を取得
      while(leng>=0){  // 文字数分'\0'をセット
        fseek(fp, posi+leng-1, SEEK_SET);
        leng--;
        fputc('\0', fp);
      }
      fseek(fp, posi+1, SEEK_SET);  // 次の行の先頭にセット
    }
    posi = ftell(fp);
  }
  // ファイルクローズ
  fclose(fp);
  return TRUE;
}

1行あたりIPアドレスが1つ書いてあるテキストファイルから、指定したIPアドレスを削除するプログラムを作成しています。

r+モードでfoepnした後にfgetsで一行ずつ読み取り、指定されたIPアドレスかどうかをチェックし、該当すればその行をNULLで埋め尽くしているのですが、サクラエディタなどで開くとその行が削除ではなくNULL文字で埋め尽くされているといった現象になります。
削除するにはどうすればよいでしょうか?

ipaddress.txt
---------------------
192.168.0.1(\n)
192.168.0.2(\n)
192.16...続きを読む

Aベストアンサー

以下は1つのアイデアです。

1)削除前のファイル(A)を読込み用で、削除後のファイル(B)を書込み用で、それぞれオープンする。
2)Aを1行読む。
3)残しておきたいデータならば、Bに書込む。
4)前2項を、Aを読み終わるまで繰り返す。
5)AとBをクローズする。
6)BをAにコピーする。
7)Bを削除する。
8)おしまい。

Q複数桁10進数の*桁目だけを抽出したい

タイトルがすべてと言えてしまうのですが、
例えば、int宣言された"4287"(この値は変動します)という数値があったとして、1桁目の"7"だけを別の変数へ引き抜きたいのですが、その場合にはANDによるマスク処理による演算で処理可能なのでしょうか?
また、他に良い方法などありましたら教えていただけますでしょうか?

Aベストアンサー

★10進数ですので AND は使えませんね。
・簡単なサンプルを載せますので読み取って下さい。

サンプル1:
int value = 4287;
int a[ 4 ];

a[0] = (value % 10); value /= 10; // 1桁目を取り出す
a[1] = (value % 10); value /= 10; // 2桁目を取り出す
a[2] = (value % 10); value /= 10; // 3桁目を取り出す
a[3] = (value % 10); value /= 10; // 4桁目を取り出す

サンプル2:
int value = 4287;
int a;

a = (value % 10);
value -= a;

value → 4280
a → 7
になります。

Q戻り値で構造体を返すことは可能でしょうか?

perlでは以下のように2つの戻り値が可能ですが、C言語では
それができるのでしょうか?
my (ret1, ret2) = test1();

よくやるのは、引数にポインタを渡して、内容を書き換える手を使っていますが、戻り値を複数返せたら、直感的にわかりやすいかなと思いまして・・・

Aベストアンサー

C言語から遠く離れた者ですが、

>>> よくやるのは、引数にポインタを渡して、内容を書き換える手を使っています

これが常識でしょう。これが直感的に理解できるようにC言語を身に付ける必要があるのではないでしょうか。


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング

おすすめ情報