AIと戦って、あなたの人生のリスク診断 >>

ファイル名である文字列からbasenameを(スマートに)取得したいです。
Perlでは何も考えなくてもできたのですが、C(もしくはC++)では次のようなやりかたしか思いつきません。
これでできているので問題ないのですが、何だかモヤモヤします。
また、このやり方では拡張子はピリオド含めて4文字であること前提なのもモヤモヤの原因です。
Perlのようにもっとスマートなやりかたはないでしょうか?

---------------------------------
char filename[] = "test.dat";
char basename[128];

strncpy(basename, filename, strlen(filename)-4);
basename[strlen(filename)-4] = '\0';
---------------------------------

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

A 回答 (5件)

拡張子がないとか、base自体に.を含むとか、考えると、例えばVCなら_splitpath関数を使うのが一番スマートかも。



C++ならstd::string::find_last_ofで.を探して、
std::string::substrやiterator等の組み合わせで部分文字列を抽出するとか。
    • good
    • 0
この回答へのお礼

_splitpath関数ですか。知らなかったのでちょっと調べてみます。
VC以外はダメなんですかね?
ちょっとそこのところが躊躇されますが、自分はVCなので使ってみます。
スマートそうな匂いがしています。

お礼日時:2006/08/18 22:59

最後のピリオドを探すのであれば、strrchrを使えば一発でできますが、foo.tar.gzのようなファイル名の場合、本当にそれでよいのか、いまいち不安が残りますね。

    • good
    • 0

 


 発展・・・かな?

#include <stdio.h>
#include <string.h>

int main(void)
{
char filename[] = "test0.test1.test2.dat";
char *pch, *temp;

pch = NULL;
for(temp = filename; (temp = strchr(temp, '.')) != NULL; temp ++) pch = temp;
if(pch != NULL) *pch = '\0';
printf("%s", filename);
return 0;
}
 
    • good
    • 0
この回答へのお礼

ありがとうございます。
strchrも検討してみます。

お礼日時:2006/08/18 23:05

 


#include <stdio.h>
#include <string.h>

int main(void)
{
char filename[] = "test.dat";
char *pch;

if((pch = strchr(filename, '.')) != NULL) *pch = '\0';
printf("%s", filename);
return 0;
}
 
    • good
    • 0

1.ファイルネームが格納された文字列を先頭から順に一文字ずつピリオドかどうかをチェックする。



2.ピリオドでない場合はベースネームを格納する文字列にその文字をコピー、ピリオドの場合は'\0'を書き込んで関数を抜ける

っていうのはどうでしょう?
    • good
    • 0
この回答へのお礼

ありがとうございます。
この方法が一番オーソドックスで自然かもしれないです。

お礼日時:2006/08/18 22:53

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

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

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

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

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

Qファイルやディレクトリの存在確認を行う方法

ファイルをオープンするのはfopenでOKですが、ファイルやディレクトリの存在確認を行う方法が知りたいです。

何か組み合わせて作るものなのでしょうか?
perlとか便利な演算子があるのですが、C/C++って器用ではないですね。
これは処理系?依存の内容ですか?

私の環境は VC6, VC2005 Windows2000です。

Aベストアンサー

int access(const char* path, int mode);
int stat(const char* path, struct stat* sb);

かな?
MSDN を引くと _access_s() を使えとか書いてあるけど。

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が...続きを読む

Q絶対パスからのファイル名の切り離し

VC++6.0でCのコードを書いています。
絶対パスからのファイル名の切り出し方に関して質問です。
FILEPATH="C:\TEST\test.txt"
というファイルがあるとして
"C:\TEST"と"test.txt"の部分を切り離したいと思っています。
フォルダ位置は可変("C:\TEST\TEST"が来ることもある。)
このときに
FILEPATHの先頭アドレスから最後まで
\マークがいくつ来ているか判断して
最後の\マーク以降とそれ以前を
strcpyなどでコピーすればできると思うのですが、
この際、
1.\マークの数を数える
2.最後の\マークの手前までパス名をコピー
3.最後の\マーク以降をファイル名としてコピー
という作業が必要になると思いますが
もっと簡単に行う方法があればお教えいただければと思っています。
(標準関数を使用して・・・など)
よろしくお願いします。

Aベストアンサー

_splitpath 関数を使用すれば簡単だと思います。
サンプルを示せば、こんな感じです。(見にくいですが)

#include <stdlib.h>
char path[_MAX_PATH]; /* _MAX_PATH260 */
char drive[_MAX_DRIVE]; /* _MAX_DRIVE 3 */
char dir[_MAX_DIR]; /* _MAX_DIR256 */
char name[_MAX_FNAME]; /* _MAX_FNAME256 */
char ext[_MAX_EXT]; /* _MAX_EXT256 */

_splitpath("C:\TEST\test.txt", drive, dir, name, ext);
_makepath(path, drive, dir, NULL, ext); /* C:\TEST\ */
_makepath(path2, NULL, NULL, name, NULL); /* test.txt */

C:\TEST\の後ろの\をカットしたい場合は、下記を追加して下さい。
int len;
len = strlen(path);
if (path[len-1] != '\\')path[len-1] = '\0';

_splitpath 関数を使用すれば簡単だと思います。
サンプルを示せば、こんな感じです。(見にくいですが)

#include <stdlib.h>
char path[_MAX_PATH]; /* _MAX_PATH260 */
char drive[_MAX_DRIVE]; /* _MAX_DRIVE 3 */
char dir[_MAX_DIR]; /* _MAX_DIR256 */
char name[_MAX_FNAME]; /* _MAX_FNAME256 */
char ext[_MAX_EXT]; /* _MAX_EXT256 */

_splitpath("C:\TEST\test.txt", drive, dir, name, ext);
_makepath(path, drive, dir, NULL, ext); /* C:\TEST\ */
_makepath(path2, NULL, NULL, n...続きを読む

Qint型からchar型への変換

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

Aベストアンサー

#include <stdio.h>


char buf[5];
int no;

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

QLNK2019: 未解決の外部シンボルのエラーが出る

Microsoft Visual Studio 2008
Version 9.0.21022.8 RTM
Microsoft .NET Framework
Version 3.5 SP1
----------------------------------------------------------------
新しいプリジェクト→Win32 コンソール アプリケーション(ソリューションのディレクトリを作成 チェック外す)→Windows アプリケーション(空のプロジェクト チェック外す)
----------------------------------------------------------------
 プログラム

 mymain.cpp
#include "myhelper.h"
#include "mymain.h"

//自キャラのデータ
Point2D g_jikipos = {40, 400};//自キャラの座標

//画像ハンドル
int g_jikiimage[11];

//色々なファイルの読み込み
int LoadFiles(){
//画像ファイル読み込み
if(LoadDivGraph("media\\player01.bmp",
11,11,1,64,64,g_jikiimage) == -1) return -1;

return 1;
}


 mymain.h
//他から呼び出させるMyMainの関数
void MyMain();
int LoadFiles();


 myhelper.h(サンプルなので打ちミスはない)
#include "DxLib.h"
#include <limits.h>
#include <math.h>

//構造体宣言
//座標またはベクトルを記録する構造体
struct Vector{
float x,y;
};
typedef Vector Point2D;
//線を記録する構造体
struct Line2D{
Point2D startpos, endpos;
float katamuki;//傾きをラジアン値で記録
Vector speed;//移動している場合は速度をセット
};
//球体を記録する構造体
struct Ball2D{
Point2D position;
float hankei;//半径
};
//四角形を記録する構造体
struct Rect2D{
Point2D lefttop;
Point2D rightbottom;
float width;
float height;
};


//ライブラリ関数
Point2D PosInView(Point2D in);
int XInView(float inx);
int YInView(float iny);
void ScrollToLeft(float jikiposx);
void ScrollToRight(float jikiposx);
void ScrollToUp(float jikiposy);
void ScrollToDown(float jikiposy);
void DrawLineInView(float x1, float y1, float x2, float y2, int Color, int Thickness);
void DrawCircleInView(float x, float y, float r, int Color, int FillFlag);
void DrawAnimation(float x, float y, double ExtRate, double Angle,int TurnFlag,
int *imgarray, int allframe, float fps);
//ベクトル関数
Vector CreateVector(Vector in, float veclen);
Vector AddVector(Vector v1, Vector v2);
Vector SubVector(Vector v1, Vector v2);
Vector AddVectorInFrameTime(Vector pos, Vector speed);
Vector AddVectorInFrameTime2(Vector pos, Vector speed, Vector accel);
Vector Normalize(Vector in);
Vector RotateVector(Vector in, float radian);
float VectorLengthSquare(Vector in);
float DotProduct(Vector v1, Vector v2);
float CrossProduct(Vector v1, Vector v2);
void SetLine2DKatamuki(Line2D *in);
void DrawLine2D(Line2D in, int Color, int Thickness);
void DrawBall2D(Ball2D in, int Color, int Fill);
//当たり判定関数
bool HitTestLineAndBall(Line2D linein, Ball2D ballin);
bool IsPointAtLineFace(Line2D linein, Point2D ptin);
bool HitTestLineAndLine(Line2D line1, Line2D line2);
bool HitTestBallAndBall(Ball2D a, Ball2D b);
bool HitTestPointAndBox(Rect2D rect, Point2D pt);
//タイマー関数
void SetSimpleTimer(int idx, int time);
int GetPassedTime(int idx);


//グローバル変数
extern float g_frametime;
extern Rect2D g_framerect;//画面領域(当たり判定)
extern Point2D g_current_field_pos;//現在の左上座標
extern Rect2D g_stagesize;//ステージサイズ

//定数宣言
const float ZEROVALUE = 1e-10f;
const float PIE = 3.1415926f;
const int SCROLL_LIMIT = 200;
----------------------------------------------------------------
 エラー内容
1>myhelper.obj : error LNK2019: 未解決の外部シンボル "void __cdecl MyMain(void)" (?MyMain@@YAXXZ) が関数 _WinMain@16 で参照されました
1>C:\Documents and Settings\Owner\My Documents\Visual Studio 2008\Projects\my\Debug\my.exe : fatal error LNK1120: 外部参照 1 が未解決です
1>my - エラー 2、警告 0
ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ
----------------------------------------------------------------
画像を貼り付けときます
(見えにくい場合→http://www.dotup.org/uploda/www.dotup.org154142.jpg.html)
初心者なのでわかりやすくお願いします

Microsoft Visual Studio 2008
Version 9.0.21022.8 RTM
Microsoft .NET Framework
Version 3.5 SP1
----------------------------------------------------------------
新しいプリジェクト→Win32 コンソール アプリケーション(ソリューションのディレクトリを作成 チェック外す)→Windows アプリケーション(空のプロジェクト チェック外す)
----------------------------------------------------------------
 プログラム

 mymain.cpp
#include "myhelper.h"
#include "mymain.h"

//自...続きを読む

Aベストアンサー

ファイル構成から推測するに
mymain.cpp というファイルに
void MyMain(void) {
// ここに処理を書く
}
という関数が必要なようです。

Q#defineの定数を文字列として読み込む

#define A "xxx"
#define B "yyy"
と定義しておいて

scanf("%s", str)
で読み込んだ文字列strが
"xxx"だった場合、"yyy"だった場合のように分岐したいのですが
このとき

if(str == "xxx")
のように中身を指定するのではなく

if(str == AA)
のように定数で分岐させることってできますか?

上記のままではできませんが、何か特別な関数とかでできるのでしょうか?

Aベストアンサー

こんにちは。

やりたいことの解釈ですが、(※勘違いの場合はすみません。)

1)マクロの名前(定義名)が文字列として格納された文字列 str があるとする。
 例)
   #define A "xxx"  //マクロ名=A
   char str[] = "A";   //"A"はマクロ名

2)上記の文字列 str を関数 func に渡す際に、マクロ名ではなくそのマクロで
  定義された文字列を渡したい。
 例)
   func( str );    //←この場合
    ↓
   func( "xxx" );  //←として展開される

ということで宜しいでしょうか?

だとした場合、少し回りくどいやり方かもしれませんが、以下のような文字列
変換用のマクロを定義してみては如何でしょうか?
※基本的には、他の回答者の方と同じように strcmp関数 を使用します。

■マクロ例
==============================
//文字列を定義したマクロ …※1
#define A "xxx"
#define B "yyy"

//引数を文字列として取得するマクロ
#define GETSTR(x) #x

//引数をマクロ名としてそのマクロで定義された文字列を取得するマクロ …※2
//注)<string.h>がインクルードされていることを前提とする
#define STR2MAC(str) \
!strcmp(str,GETSTR(A))? A : \
!strcmp(str,GETSTR(B))? B : str
==============================

上記マクロを使用して、関数 func にマクロ名が格納された文字列 str を
渡す場合は、
   func( STR2MAC( str ) );
のような記述になります。

前提として、※2のマクロ内でstrcmp関数を用いて文字列の照合を行って
いますので、<string.h>のインクルードが必要になります。

また、※1の文字列を定義するマクロの種類(パターン)を増やす場合、
※2のマクロの判定文もそれに合わせて増やす必要があります。

上記のマクロを使用したサンプルソースを下記に掲載致します。
注)エラー処理は行っていません。

■サンプルソース
==============================
#include <stdio.h>
#include <string.h>

//文字列を定義したマクロ
#define A "xxx"
#define B "yyy"

//引数を文字列として取得するマクロ
#define GETSTR(x) #x

//引数をマクロ名としてそのマクロで定義された文字列を取得するマクロ
//注)<string.h>がインクルードされていることを前提とする
#define STR2MAC(str) \
!strcmp(str,GETSTR(A))? A : \
!strcmp(str,GETSTR(B))? B : str

//プロトタイプ
void funcHoge( const char *str );

int main(void)
{
char sArg[128];

printf( "A or B ?>" );
scanf( "%s", sArg );

printf( "string1: %s\n", sArg );
funcHoge( STR2MAC(sArg) );

return 0;
}

void funcHoge( const char *str )
{
printf( "string2: %s\n", str );
}
==============================

■上記サンプルの実行結果
≫実行その1≪
A or B ?>A
string1: A
string2: xxx

≫実行その2≪
A or B ?>B
string1: B
string2: yyy

≫実行その3≪
A or B ?>hoge
string1: hoge
string2: hoge

以上です。

こんにちは。

やりたいことの解釈ですが、(※勘違いの場合はすみません。)

1)マクロの名前(定義名)が文字列として格納された文字列 str があるとする。
 例)
   #define A "xxx"  //マクロ名=A
   char str[] = "A";   //"A"はマクロ名

2)上記の文字列 str を関数 func に渡す際に、マクロ名ではなくそのマクロで
  定義された文字列を渡したい。
 例)
   func( str );    //←この場合
    ↓
   func( "xxx" );  //←として展開される

ということで宜しいでしょう...続きを読む

QC ファイル出力で、フォルダがない場合でも作成する方法

先日、皆さんに教えていただき

Cで出力ファイルを指定のフォルダに出す方法が上手く出来ました。
具体的には、↓こうやって指定しました。
sprintf( buff, "%s\\%s", path, filename );

やっていて思ったのですが、
この方法だと、指定フォルダが最初から無いとエラーが出てしまいます。
フォルダが無かったら、作成し、その中にファイルを出力していってくれる。という方法はできるものなのでしょうか?

もしできるようなら教えて下さい!!
よろしくお願いします!

Aベストアンサー

★回答ではないが余談。
・koko_u_ さんありがとう。
 気づくとアンダーバーの関数名で置き換わっているみたいですね。
 他にも気づくといろいろ置き換わっていますね。
 C 関数、最近使っていないのでアンダーバーの関数名で調べてみます。
・ありがとうございました。

●質問者さんへ。
・_mkdir() 関数が使える場合はその関数でもフォルダ(ディレクトリ)が作成できます。
 それでは。

参考URL:http://www5c.biglobe.ne.jp/~ecb/c/12_14.html

QC++で文字列の右端から特定の文字までの文字列を

C++で文字列の中から,文字列の右端から特定の文字までの文字列を取り出すというものを作りたいと思っています。

右端から○文字取り出す。といった感じのコードは書けるのですが、特定の文字まで、というのがどうもうまくいきません。こちら、良いアドバイスをいただける方がいましたらよろしくお願いします。

例:ファイル名を抽出
文字列\system32\notepad.exeからnotepad.exeの部分だけを取り出したい。というものです。
初めに見つけた\まで取り出す・・とやればよいのでしょうが、その方法が今ひとつ良くわからないので、どうかご助力お願いいたします。

Aベストアンサー

具体的なコードにもよりますが、

> 右端から○文字取り出す。といった感じのコードは書けるのですが

だったら、ほぼできていると思います。

char src[1000]; に文字列が入っているとして、

そのコードに、

int j = src[] にある、最後の文字を示すインデックス
for(int i = 0; i < ○; i++)
{
src[j] を取り出す;
j--;
}

という部分があるなら、

while(src[j] != '\\')

に書き直すだけ。

または、

for(int j = src[] にある、最後の文字を示すインデックス; (j >=0 ) && src[j] != '\\'; j--)

にするとか。

でも、「どうもうまくいきません」なら、「こういうことをしたら、こうなってしまいました」というのがあるほうが親切ですね。

Qfopne で失敗する原因

fopenで失敗する原因とはなんですか?

Aベストアンサー

#1の方の回答に加えて...

・ファイル名の文字列がでたらめ(存在するかどうか以前の問題)
・指定したファイル名が実はディレクトリだった。
・ファイル名に空ポインタまたは不正なポインタを渡した。
・オープンモードに空ポインタまたは不正なポインタを渡した。
・オープンモードの形式が不正
・メモリ不足でバッファ(実装によってはファイル記述子も)の割り付けに失敗した。
・同名の関数またはマクロをユーザーが定義した。
・関数原型なしで呼び出した。
・他のスレッド等で、同じファイルに対する操作中(再入可能とは限らないので)

QCStringからchar*への型変換について教えてください。

以前の質問に

int型 → CString型/char型

がありましたが、

CString型をchar*型に変換する方法を
教えていただければありがたいです。

MSDNで「LPCTSTRキャスト」が説明されていましたが、
例が載ってないのでよくわかりませんでした。

よろしくお願いします。

Aベストアンサー

目的にもよりますが一時的にchar配列として使いたいならCString::GetBuffer()が利用できます。
char配列としての利用が終わったらCString::ReleaseBuffer()する必要がありますが。

直接CString内の文字列を扱う必要があるならCString::operator LPCTSTRで文字列ポインタが得られます。
ただし、CStringオブジェクトをいじると無効ポインタなる可能性があるので気をつけてください。

MSDNのMicrosoft Foundation Classリファレンス→CString→クラスメンバで確認してください。


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

人気Q&Aランキング