- ベストアンサー
C言語で文字列を書き換える方法とは?
- C言語で文字列を書き換える方法について、基礎的な質問ですが教えてください。
- 関数内で文字列を書き換えることができない場合、どのような方法がありますか?
- 例えば、C言語で文字列を書き換える方法を示す簡単なコードの例を教えてください。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
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という関数を代わりに使うケースもあります。
その他の回答 (5)
- 和泉 博(@hiroshi09s)
- ベストアンサー率54% (59/109)
>例えば以下のようなソースで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文字列の最後まで変換 }
お礼
すみません、ABCをDEFにというのは一例で 連番にしたいというわけではなかったです。 でも、連番だとそのような考え方もあるのですね。 ありがとうございます。
- m-take0220
- ベストアンサー率60% (477/782)
例えば 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なので、文字列は変更されません。
お礼
アドレスを代入と考えると分かりやすいですね。 ありがとうございます。
- kmee
- ベストアンサー率55% (1857/3366)
Cでは「文字列」という型は無くて、「ポインタ/配列が示す場所から0までのchar」を文字列として扱う、というルールで運用しています。 プログラムを作る際は、他の数値型とは分けて、他の数値型の配列やポインタを扱うようなつもりで考える必要があります。 たとえば void func(int *n2) { int n0={1,2,3} ; n2 = n0 ; } これが、実質何もしない、ということはおわかりですね? あなたの書いたfunc関数は上のintをcharの置き換えただけのものです。
お礼
文字列に関しての理解が浅かったです。 ありがとうございます。
- TT414
- ベストアンサー率18% (72/384)
一文字ずつ変えたい場合は以下のようにして書き換えてください。 void func(char *str2) { str2[0] = "D"; str2[1] = "E"; str2[2] = "F"; }
お礼
配列に直接入れる必要があるのですね。 ありがとうございます。
- yama1718
- ベストアンサー率41% (670/1618)
ポインタの理解が足りませんね。 str2自体は仮引数なのでfunc関数から抜けると消滅します。 だからstr2をいくらいじっても無駄なのです。 ポインタそのものをいじるのじゃなくて、ポインタが指しているメモリに書き込まないとね。 void func(char *str2) { strcpy(str2, "DEF"); } これでOK
補足
ありがとうございます。 func関数から抜けると消滅するということは分かるのですが int型の場合、参照で渡して *str2 = 10; のようにすればstr1も置き換わると思います。 char配列型の場合は似たような記述方法はないのでしょうか? strcpyのような関数を使わなければ無理ですか?
お礼
確かにサイズは気にしていなかったので そういう危険性もあるのですね。 ありがとうございます。