質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

2回答

277閲覧

ポインタを使って関数内で文字列を操作する方法について

err0r

総合スコア20

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2019/04/18 15:01

文字列から数字を除去して表示する関数を作成したのですが、
関数内では数字が正しく除去されているのですが、
メインプログラムで関数を呼びだしても数字が除去されません。
どこがおかしいのか教えていただけないでしょうか?

#include <stdio.h> #include <string.h> #include <ctype.h> void digit(char* s){ char tmp[256]; int i,j = 0; for(i=0; i < strlen(s); i++){ if (!((*(s+i) >= '0') && (*(s+i) <= '9'))) tmp[j++] = *(s+i); } tmp[j+1] = '0'; //末尾にNULL文字を追加 s = tmp; //ポインタが配列tmpを指すように変更 printf("関数内のポインタSが指す文字列は%s\n", s); } int main(void){ char* str = "abc4de5fg"; digit(str); printf("メイン関数のポインタstrが指す文字列は%s", str); return 0; }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

ここが問題です。

C

s = tmp; //ポインタが配列tmpを指すように変更

ポインタ変数自体を関数内でいくら書き換えようと、呼び出し元には影響しません。
簡単に対応できそうな方法は一つ。

  • ポインタのポインタを渡す 非推奨。理由はコメント欄に記載しています。

あるいは、strを文字型配列として確保すれば()、次の二つの方法も選べます。

  • tmpを使わず、sが指し示す先を直接書き換える
  • strncpy

註: 文字列リテラルで確保した領域は読み取り専用だった筈。


ついでに、ここも変です。

C

tmp[j+1] = '0'; //末尾にNULL文字を追加

tmp[j] = '\0' としてください。
'0'はただの数字0であって、NULL文字とは呼べません。

また、jの値がループ後にどのようになっているか確認した方が良いでしょう。
現状のコードではtmp[j]の値が不定です。

投稿2019/04/18 15:10

編集2019/04/18 17:10
LouiS0616

総合スコア35660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

err0r

2019/04/18 16:30

丁寧に解説いただいてありがとうございました。 ポインタを関数に渡す場合でもコピーした値になるんですね。 関数ヘ渡す引数にポインタstrのポインタ(int** pstr)を追加して、 関数内の処理を、*pstr = tmp にすることで正しく動作するようになりました!NULL文字についての情報もありがとうございました。 ループの最後にtmp[j++] が評価されてjがインクリメントされて不定になるという事ですね。配列は宣言時に初期化するようにします。
LouiS0616

2019/04/18 16:48

一個だけ回答に致命的な抜けがありました。 tmpの生存期間はdigit関数内ですので、そのポインタを利用するならばグローバル変数にするなりstaticにするなりして延ばしてやる必要があります。
LouiS0616

2019/04/18 16:58

ただしこの場合も、複数回関数を呼び出した際の動作はおそらく期待しないものになります。 やはりポインタのポインタを利用するのではなく、strを配列として宣言しその中身を書き換えるか、受け取り用の配列を呼び出し元で用意した方が良いでしょう。
err0r

2019/04/19 15:06

補足ありがとうございました。おっしゃる通りですね。関数で定義した値を指すよりも配列の中身を書き換えたほうがコードの依存性がないので簡潔ですね。勉強になりました。
guest

0

既に解決済みとなっていますが、こんな感じ?

C

1void digit(char* s) 2{ 3 char *src = s; 4 char *dst = s; 5 while (*src != '\0') { 6 if (!isdigit(*src)) *dst++ = *src; 7 src++; 8 } 9 *dst = '\0'; 10 printf("関数内のポインタSが指す文字列は%s\n", s); 11} 12 13int main(void) 14{ 15 char str[] = "abc4de5fg"; // []で宣言するので、書き換え可 16 digit(str); 17 printf("メイン関数のポインタstrが指す文字列は%s", str); 18 return 0; 19} 20

投稿2019/04/19 15:38

pepperleaf

総合スコア6383

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

err0r

2019/04/21 16:25

ありがとうございます。 同じ処理でもこんなに簡潔に記述できるんですね。。 同じ所を指すポインタを複数作れるのは知りませんでした。 次回から参考にさせていただきます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問