C言語で文字列を書き換える方法とは?

このQ&Aのポイント
  • C言語で文字列を書き換える方法について、基礎的な質問ですが教えてください。
  • 関数内で文字列を書き換えることができない場合、どのような方法がありますか?
  • 例えば、C言語で文字列を書き換える方法を示す簡単なコードの例を教えてください。
回答を見る
  • ベストアンサー

mainから渡した文字列を関数内で書き換え

非常に基礎的な質問で申し訳ないのですが mainから渡した文字列を関数内で書き換えることができません。 int型の整数やchar型一文字はできるのですが。。。 例えば以下のようなソースでmainのABCをDEFに書き換えたいとき どのようにすればいいのでしょうか。 (関数の戻り値で変更という方法以外で) 以下のソースでは値は書き換わりませんでした。 void func(char *str2) { str2 = "DEF"; } int main() { char str1[20] = "ABC" printf("%s", str1); //ABC func(str1); printf("%s", str1); //DEFになるようにしたい }

  • oxfax
  • お礼率27% (57/209)

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

Cには値渡し(Call by value)しかないので、str2に直接値を代入しても呼び出し元では値が変わらないですね。 例えば、次のようにすると呼び出し元でも値が変わります。 void func(char *str2) { str2[0] = 'D'; str2[1] = 'E'; str2[2] = 'F'; } Cの文字列変数は文字列の先頭文字に対するアドレスが入っているだけなので、funcが呼ばれたとき、str2にはmain()のstr1のアドレスが入っています。元の書き方ではこのstr2に"DEF"という文字列の先頭文字に対するアドレスを代入しているだけなので、main()のstr1の中身は変わりません。余談ですが、このようにアドレスを格納した変数のことをポインタといいます。 ちなみに、同じ事を文字列操作関数を使ってやるとこんなかんじです。 #include <string.h> void func(char *str2) { strcpy(str2, "DEF"); } この場合、呼び出し元はstr2の最大サイズを知らず、多めに書きこんでしまう可能性があります。そして、確保した容量以上にメモリーを使用するとプログラムを異常終了させたり、プログラマの意図しない誤った動きをさせたりすること (バッファ溢れ攻撃) が可能となります。 よって、この様なプログラムを書いたほうがよりよいでしょう。 #include <stdio.h> #include <string.h> void func(char *str, size_t str_size) { strncpy(str, "DEF", str_size - 1); str[str_size - 1] = '\0'; } int main(void) { char str1[20] = "ABC"; printf("%s\n", str1); func(str1, sizeof(str1)); printf("%s\n", str1); return 0; } strncpy(str, "DEF", str_size - 1);はstr_size - 1の長さだけ"DEF"を書き込む関数で、最期の一文字をNULL文字で終了させない場合があるのでstr[str_size - 1] = '\0';しないといけません。この問題を解決するためにstrlcpyという関数を代わりに使うケースもあります。

oxfax
質問者

お礼

確かにサイズは気にしていなかったので そういう危険性もあるのですね。 ありがとうございます。

その他の回答 (5)

回答No.6

>例えば以下のようなソースでmainのABCをDEFに書き換えたいとき、どのようにすればいいのでしょうか。 「ABC」を「DEF」の同じ連番記載に換えたいということですよね。 やり方は2通りあると思います。 1つはあなたが承知の文字定数「DEF」に換える場合と、もう一つは元の文字について一定の幅を持たせて任意の「DEF」に換える場合です。 前者の場合は #1 さんの strcpy()関数を使うのが良いと思います。ただし、string.hヘッダーファイルを include しなければなりません。 後者の場合は↓に示す方法で、与えられた文字列str2全部に対して一定の幅を持たせて変換するものです。 まあ、結局は好みの問題でもありますが...。 /* 定数3の理由:A,B,C,D -> 4番目のD-1番目のA */ void func(char *str2){ while(*str2) *str2++ += 3; //str2文字列の最後まで変換 }

oxfax
質問者

お礼

すみません、ABCをDEFにというのは一例で 連番にしたいというわけではなかったです。 でも、連番だとそのような考え方もあるのですね。 ありがとうございます。

回答No.5

例えば void testmain() { int i=0; test(&i); printf("%d",i); } void test(int*p) { *p=1; } の場合、&iが0x1000とすると、test内では0x1000の内容が1に変更されるため、testmainでもiの値が変わります。 ところが、 void testmain2() { char str[10] = "ABC"; test2(str); printf("%s",str); } void test2(char* p) { p="DEF"; } としたとき、strが0x2000、"DEF"の先頭アドレスが0x3000とすると、test2内ではpの値が0x3000に変更されるだけで、0x2000にあるデータは"ABC"のままです。当然、testmain2ではstrの値は0x2000なので、文字列は変更されません。

oxfax
質問者

お礼

アドレスを代入と考えると分かりやすいですね。 ありがとうございます。

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.4

Cでは「文字列」という型は無くて、「ポインタ/配列が示す場所から0までのchar」を文字列として扱う、というルールで運用しています。 プログラムを作る際は、他の数値型とは分けて、他の数値型の配列やポインタを扱うようなつもりで考える必要があります。 たとえば void func(int *n2) { int n0={1,2,3} ; n2 = n0 ; } これが、実質何もしない、ということはおわかりですね? あなたの書いたfunc関数は上のintをcharの置き換えただけのものです。

oxfax
質問者

お礼

文字列に関しての理解が浅かったです。 ありがとうございます。

  • TT414
  • ベストアンサー率18% (72/384)
回答No.2

一文字ずつ変えたい場合は以下のようにして書き換えてください。 void func(char *str2) { str2[0] = "D"; str2[1] = "E"; str2[2] = "F"; }

oxfax
質問者

お礼

配列に直接入れる必要があるのですね。 ありがとうございます。

  • yama1718
  • ベストアンサー率41% (670/1618)
回答No.1

ポインタの理解が足りませんね。 str2自体は仮引数なのでfunc関数から抜けると消滅します。 だからstr2をいくらいじっても無駄なのです。 ポインタそのものをいじるのじゃなくて、ポインタが指しているメモリに書き込まないとね。 void func(char *str2) {   strcpy(str2, "DEF"); } これでOK

oxfax
質問者

補足

ありがとうございます。 func関数から抜けると消滅するということは分かるのですが int型の場合、参照で渡して *str2 = 10; のようにすればstr1も置き換わると思います。 char配列型の場合は似たような記述方法はないのでしょうか? strcpyのような関数を使わなければ無理ですか?

関連するQ&A

  • abcが、入力された文字列内にあるかどうかを表示するプログラム

    文字列strの中にabcが含まれていれば、1を返し、含まれていなければ0を返すプログラムが分かりません。 C言語の問題で下記のものが分かりません。どなたか知恵を貸してください。 ユーザが文字を入力し、CTRL+Zが押されるまで、半角英数字の入力(最大でも1000文字)を受け付ける。文字列「abc」が、入力された文字列内にあるかどうかを表示するプログラムを作成する。ユーザが入力した文字列が3文字未満はabcがありませんと表示させる。 そのプログラム内で以下の関数を完成させる。 int str_srch_abc(char str []) 文字列strの中にabcが含まれていれば、1を返し、含まれていなければ0を返す関数とする。 (例えばabcは連続でabcの時だけ1を返し、asbscなどはoを返します。) ちなみに自分なりにやってみたのですが、ここまでしかできませんでした。 #include<stdio.h> int main() { int str_srch_abc(char str []); char str[1000]; int ch=0, j=0; printf("半角英数字を入力してください"); scanf("%s",str); while((ch=getchar())!=EOF){ str[j]=ch; j++; } str[j]='\0'; printf("%s",str); return(0); }

  • 文字列のコピー

    C言語で、文字列をコピーする関数で、処理が止まってしまいます。 以下が実行したプログラムです。 #include<stdio.h> #include<string.h> void copy(char *str2 ,char *str3){ strcpy(str2,str3); } void input(char* str){ scanf("%s",str); } int main (void){ char *a; char *b="TEST"; printf("%s\n",b); input(a); copy(b,a); printf("%s",b); return(0);} copy(b,a);で処理が止まってしまいます。入力した文字列を表示できるように、御指摘お願いします。

  • 文字列ポインタとgets関数の関係について。

    以下のプログラムはコンパイルは出来ますが、 実行するとクラッシュしてしまいます。 gets関数は char *gets( char *str ); と定義されているので文字列の先頭アドレスを返すはずですが 何故このプログラムはエラーが出るのでしょうか・・。 #include <stdio.h> int main ( void ){  char *p, *s;  p = gets(s);  printf("%s", p);  return 0; }

  • 文字列の扱い方

    初歩的な質問ですみません… str文字列からcという文字を見つけたら添字を返すという関数を作ったのですが、 iにこの関数を代入して、if文の制御式にiを使って比較するまでは正常なのですが、 真文にiを使うと何故か偽文(という言い方でいいのでしょうか…この場合("そんな値はありません。"というところです)が実行されてしまいます。 よろしければご教授お願い致します。 #include <stdio.h> int str_char(const char str[],int c) { int len = strlen(str); int i; for (i = 0;i < len;i++) { if (str[i] == c) return i; } return -1; } int main() { char str[64] = "Fucking Brutal Death Metal"; int ch,i; printf("どの文字を調べますか?"); scanf("%c",&ch); i = str_char(str,ch); if (i >= 0) printf("その文字は%d番目にあります。",str_char(str,ch) + 1); //何故かiだと動かない else printf("そんな値はありません。"); return 0; }

  • 文字列処理関数について

    おみくじのプログラムを書きました。初めのが私のもので、次のが参考書のものなのですが、なんでわざわざ 文字列処理関数を使うのかがわかりませんでした。 教えてください!! int main() {   int r =0;   int i =0;   srand(time(NULL));   r = rand()%3+1;   for(i=0;i<2;i++){    if(r == 1)    {  printf("大吉:充実した1日\n");    }    else if(r == 2)    {  printf("小吉:充実した1日\n");    }    else    {       printf("凶:衝動買いに注意\n");    }    return 0; } ********************** ********************** main(){     int kuji;     char kekka[6];     char str[45];     srand(time(NULL));     r = rand()%3+1;     switch(kuji){     case 1:           strcpy(kekka,"大吉");         strcpy(str,"金運アップ");         break;    /*case2,3は省略します*/           default:    break; } printf("%s:%s",kekka,str); return 0; }

  • char* を渡したとき、不適切なPtrが出る問題

    こんばんは。プログラムを勉強中の学生です。 詰まった部分があり、関連しそうな部分を勉強しましたが、問題が解決しなかったので、 こちらで質問させて頂きます。 今、とあるクラスで、 class Test{ ........................................ public: int Func1(char* str,){ unsigned int n = 0; while(str != "\0"){ n += *str; str++;}          ←ここに<不適切なPtr> return n % 3; } void Func2(char* str){ int i; i = Calc(str); ..................................... ............................ } }; のように宣言し、main()関数で、 int main(){ Test test; test.Func2("ABC"); // Case1: エラーは起こらない char s[]={"ABC"}; //Case2:不適切なPtrとなる。 test.Func2( s ); } としていますが、上記のように、"ABC"を直接入れたときのみ、うまくいき、 他の方法で、char型のポインタを代入した際には、不適切なPtrと出てしまいます。 この原因を教えていただけないでしょうか? 最終的には、 cin >> s ; などのように、キーボードから入力した値(文字列)を使いたいのですが、 現段階ではmain関数で "ABC"のように書かなければならず困っています。

  • 文字を置き換える関数で分からないことがあります。

    文字列strの中にある、文字列bagと共通の文字を空白に置き換える関数とその動作を確認するための、空白に置き換えた文字列strを表示するプログラムですが、戻り値が正しくないそうです。 ヒントでもいいのでどう直せばいいのかどなたかお教え下さい。 #include <stdio.h> char str_space(char str[], char bag[]){ int a, b, c, d; for(a = 0; a <= 99; a++){ if(str[a] == '\0'){ c = a; break; } } for(a = 0; a <= 99; b++){ if(bag[a] == '\0'){ d = a; break; } } for(a = 0; a <= c; a++){ for(b = 0; b <= d; b++){ if(str[a] == bag[b]){ str[a] = ' '; } } } return str[]; } int main(void){ char str[100], bag[100]; scanf("%s", str); scanf("%s", bag); printf("%s", str_space(str, bag)); return 0; }

  • [C]char型のダブルポインタ

    粗雑で申し訳ありませんが、 以下のソースをコンパイルできましたが、 うまく実行できません。 自分なりに間違いがないと思うのですが、 間違い等をご指摘頂ければ助かります。 #include <stdio.h> void func(char **ptr) ptr[][10] か (*ptr)[] なら通る *ptr[] は通らない { printf("----- func -----"); printf("%s\n", *ptr); printf("%c\n", **ptr); putchar('\n'); } int main(void) { char str[5][10] = {"AAAAA", *str[] にすると func で **ptr で通る "BBBBB", "CCCCC", "DDDDD", "EEEEE", }; printf("----- main -----"); printf("%s\n", *str); printf("%c\n", **str); putchar('\n'); func(str); return (0); } 実行結果 ----- main ----- AAAAA A ----- func ----- Bus error (core dump) 関数への受け渡しで、型が違うというお叱りを受けますが、 コンパイルはできました。 コンパイラはCCです。 ではよろしくお願いします。

  • c言語の問題

    以下のプログラムをコンパイルし、実行したところ、次のような画面が表示された。下記の関数定義部分を補いなさい。 gcc test.c ./a.out abc def answer = defabc 以下ソースコード #include<stdio.h> void stradd(char A[], char B[]); int main(){ char str1[100], str2[100]; scanf("%s", str1); scanf("%s", str2); stradd(str1, str2); printf("answer = %s\n", str2); } void stradd(char A[], char B[]){ } よろしくお願いします。

  • プログラミング ポインタを使った文字列比較

    プログラミング ポインタを使った文字列比較 2つの文字列str1, str2を入力し,それらが等しければ0,等しくなければ1を返す関数str_compareを作り、返り値によって以下のように表示するプログラムを作れ。ただし,関数strcmpを使ってはならない。 文字列の入出力はmain関数で行い,関数str_compareの仮引数にはポインタ変数を宣言し,ポインタと間接演算子*を用いた処理を行うこと。 % ./a.out input str1 = Worldcup input str2 = Worldcup same strings % ./a.out input str1 = World input str2 = cup different strings この問題に私は次のようにプログラミングしました。 #include <stdio.h> #define MAX 100 int str_compare(char *, char *); main() { char str1[MAX], str2[MAX]; printf("input str1 = %s", str1); scanf("%s", str1); printf("input str2 = %s", str2); scanf("%s", str2); str_compare(str1, str2); if (str_compare(str1, str2) == 0) printf("same strings\n"); else if (str_compare(str1, str2) == 1) printf("different strings\n"); } int str_compare(char *s1, char *s2) { int i; for (i = 0; s1[i] != '\0'; i++) { if (s1[i] != s2[i]) { break; } } if (s1[i] == s2[i]) { return 0; } else { return 1; } } これで実行したところ、「input str1 =」の右のスペースが文字化け?してしまいます。(半角カタカナや記号が出る)ただ、その後に文字列を入力すると、正しく機能します。 これは何が悪いなのでしょうか、どなたか教えてください。

専門家に質問してみよう