• ベストアンサー

文字列の引数を元に名前を変えて返す関数

基本名と拡張子名と番号を引数として、連番ファイル名の文字列を返す関数を作っています。 例えばfor文で10回ループさせる場合、Name1に"画像"、Name2に".jpg"、Numにiを渡せば、文字列"画像00.jpg"~"画像10.jpg"が返ってくるという仕組みです。しかし、試行錯誤してもポインタの仕組みが根本的に理解できてないようなので、下に示すコードの修正と解説をお願いしてもよろしいでしょうか。ちなみにこのコードではstrcatの部分でエラーが起きます。 char FileRename(char *Name1,char *Name2,int Num) { char *FileNumber[100]; FileNumber[0] = "00"; FileNumber[1] = "01"; FileNumber[2] = "02"; FileNumber[3] = "03"; FileNumber[4] = "04"; FileNumber[5] = "05"; FileNumber[6] = "06"; FileNumber[7] = "07"; FileNumber[8] = "08"; FileNumber[9] = "09"; FileNumber[10] = "10"; FileNumber[11] = "11"; FileNumber[12] = "12"; FileNumber[13] = "13"; FileNumber[14] = "14"; FileNumber[15] = "15"; char *str; str = Name1; char *add = FileNumber[Num]; strncat(str,add,2); add[30] = *Name2; strncat(str,add,strlen(Name2)); return *str; }

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

  • ベストアンサー
  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.4

> char *FileNumber[100] = { #3では見落としてましたが、一般的に配列を初期化付きで宣言する場合は要素数は指定しません。書かれている要素の分だけ自動的に確保されるためです。 まぁ処理そのものに影響はしませんが。 char *FileNumber[] = { ... }; で、本題ですが。 #3を書いたときにはうっかりしていたのですが、現在のコードでは return result; で警告が出ていませんか? 自動変数の中身は関数を抜けたあとは保証されないので、実は char result[30]; では駄目(動いてしまう処理系も多いのが厄介)で、 static char result[30]; として静的変数にするか、もしくはこれも関数引数として呼び出し元から渡す形にするのが正しい形です。 #一応関数内部で動的確保する選択肢もありますが、関数内部で動的確保するやり方は不具合の温床になりやすいのでここでは除外します。 使われ方を見る限りだとstatic char result[30];が楽そうですが、これでも駄目な場合は一度戻り値の文字列が正常か確認してみてください。

sanato
質問者

お礼

完璧です。 その回答がなくてはいつたどり着けるか分からなかったと思います。 これからも精進させていただきます。的確な回答ありがとうございました。

その他の回答 (3)

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.3

「ポインタの仕組みが根本的に理解できていない」という自覚があるのであれば、まずは理解できるようになりましょう。 ポインタを利用した文字列操作は若干応用寄りなので基本固めをしてからでも遅くはありません。 「2桁の任意の数値を加えたファイル名を返す」ということなら#1の方法(sprintf())が簡単ですが、それはとりあえず置いておいて。 > char FileRename(char *Name1,char *Name2,int Num) 戻り値で変更後のファイル名(文字列)を渡すことを期待しているはずなのに型がcharではまずいですね。char *にしましょう。 char *FileRename(char *Name1,char *Name2,int Num) > char *str; > str = Name1; > char *add = FileNumber[Num]; > strncat(str,add,2); 止まるのはここでしょうが、 char *str = "画像"; strcat(str, FileNumber[Num]); ができないのと全く同じで、書き換えてはいけないメモリを書き換えようとしているためです。 詳しく説明するのはめんどいので「文字列リテラル」について調べてください。 これは処理用のバッファを作って対処します。 char result[30]; strcpy(result, str); strcat(result, FileNumber[Num]); > add[30] = *Name2; > strncat(str,add,strlen(Name2)); なぜ唐突にadd[30]なのかが不明ですし、その後も何をやっているのかが不明です。また確保されていないadd[30]を使おうとする事によりほぼ確実に動作異常が発生します。何もおきなかったとしてもそれはたまたまに過ぎません。 strcat()の意図を汲むとしても、ここは普通に strcat(str, Name2); だけでいいはずです。 もっともこれでは前で指摘していることと全く同じ結果になるので、前段と併せて strcat(result, Name2); となります。 > return *str; 最初でも触れてますが「文字列の先頭の文字」だけ返しても意味がありませんよね?文字列の先頭アドレスを返します。 return result; とりあえずこれだけ変更すれば元のコードでも動作はするはずです。 あとはNumの閾値チェック(0~15)を忘れずに。

sanato
質問者

お礼

詳しい説明付きでどうもありがとうございます。 おかげさまでコンソールアプリでは成功したんですが、ウィンドウズアプリで独自の画像読み込み関数の引数(const char* pFileName)に渡すとなぜか上手く表示されません。これはこの関数ネイティブの問題と見てよろしいでしょうか。 現状のリネーム関数を示します。 char* FileRename(char* Name1,const char* Name2,int Num) { char *FileNumber[100] = { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15" }; char *str; str = Name1; char result[30]; strcpy(result, str); strcat(result, FileNumber[Num]); strcat(result, "."); strcat(result, Name2); return result; } 今までは画像の読み込みに テクスチャ[0] = CreateTextureFromFile("画像00.jpg"); テクスチャ[1] = CreateTextureFromFile("画像01.jpg"); このような形で行っていたので、現在はforループにより テクスチャ[i] = CreateTextureFromFile(FileRename("画像","jpg",i)); こうしています。 何か根本的な要因があればご教示いただけると有難いです。

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.2

string.h をインクルードする必要はなかったですね。 先ほどの例を参考にして、FileRename関数を作ってみてください。

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.1

ちょっとした例です。 なお、00~10の分だけループするのであれば、10回ではなく11回です。 #include <stdio.h> #include <string.h> int main(void) { char Filename[40]; int i; for (i = 0; i <= 10; i++) { sprintf(Filename, "画像%02d.jpg", i); printf("%s\n", Filename); } return 0; }

sanato
質問者

お礼

回答ありがとうございます。 なるほどポインタを使わなくてもこんな簡単にできるんですね。 今後の参考にさせていただきます。

関連するQ&A