Cの文字列切関数
■ このスレッドは過去ログ倉庫に格納されています
0001名無しサンプリング@48kHz
NGNGab=bc=def
のような文字列を
*char[0] = "ab";
*char[1] = "bc";
*char[2] = "def";
のような配列の変数に入れたいのですが
=の数を数えた上で(この場合は3)
char ** split_num(char * str@`int n)
のようにして呼び出してみているのですが
うまくいきません。わかる方どうぞお教えください。
0002名無しさん@C厨房
NGNG00032
NGNG#include <stdio.h>
int main()
{
char str[10]="ab=bc=def";
char *p[3];
p[0]=strtok(str@`"=");
p[1]=strtok(NULL@`"=");
p[2]=strtok(NULL@`"=");
printf("%s"@`p[2]);//defと表示される
return 0;
}
0004デフォルトの名無しさん
NGNGCでやるのは面倒だぞ!
Perlとかなら簡単だが。
char** split_num(char* str @` int n)
{
char** ch;
ch = (char**)malloc(3*sizeof(char*));
ch[0] = (char*)malloc(3);
ch[1] = (char*)malloc(3);
ch[2] = (char*)malloc(4);
strcpy(ch[0] @` "ab");
strcpy(ch[1] @` "bc");
strcpy(ch[2] @` "def");
return ch;
}
これで多分OK(テストしてないんで分からん。寝起きだし)
あと split_num の返値の char** が要らなくなったらメモリを破棄する。
void split_num(char** ch)
{
free(ch[0]);
free(ch[1]);
free(ch[2]);
free(ch);
}
----------------------------
悪い例
char** split_num(char* str @` int n)
{
char* ch[3];
ch[0] = (char*)malloc(3);
ch[1] = (char*)malloc(3);
ch[2] = (char*)malloc(4);
strcpy(ch[0] @` "ab");
strcpy(ch[1] @` "bc");
strcpy(ch[2] @` "def");
return ch;
}
これだと一見うまくいくように見えるが。
ch はスタック変数なので関数を抜けた時点で無効になるのでうまくいかない。
00051
NGNGとりあえず
strtokを使ってやってみました。
char value[256][256];
char * tok;
char str[] = "ab=cd=ef";
int value_num = 0;
tok = strtok(str@`delimita);
while(tok != NULL){
// printf("%s\n"@`tok);
strcpy(value[value_num]@`tok);
tok = strtok(NULL@`delimita);
value_num++;
}
このようなかたちでできました。
が、これを関数で受け渡しができないのです。
デリミタと最初の文字列(str)を渡して
配列の配列を返すようにしたいのですが、
その場合はchar **を返すようにするのですよね。
>3さん
そうですよね。僕はperlからCへのクチなので、
文字列に関するperlの便利さを実感しています。
0006デフォルトの名無しさん
NGNGO delimiter
あとは分割された文字列をコピーして返せばいいんじゃないの?
0007デフォルトの名無しさん
NGNG0008デフォルトの名無しさん
NGNG=が連続している場合や端に=がある場合にどうしたい?
perlのsplitのような仕様を望むのなら、strtokでは駄目。
strtokは連続するデリミタを単一のものと扱う。
まあ、それ以外にも、単純な実装だとリエントラントにならないとか、
strtokはANSI/ISO標準とは言え、とかく問題の多いライブラリ関数ではある。
後は、マルチバイトキャラに対応する必要があるかどうかだな。
strtokでいいのなら、1が求めているインタフェイスとはやや
違うが、例えば以下の方法で行える。これの利点は、mallocやコピーが
不要なことだ(つまり効率がいい)。
int nsplit(char **dst@` char *src@` const char *delim@` int max)
{
int i;
char *tok;
for (i = 0@` tok = strtok(src@` delim);
(i < max) && tok;
tok = strtok(NULL@` delim))
{
dst[i++] = tok;
}
return i;
}
次のようにして使う。
int main()
{
char buff[1024];
char *field[3];
char *p;
int i@` num;
while (fgets(buff@` sizeof buff@` stdin)) {
if (p = strchr(buff@` '\n'))
*p = '\0';
num = nsplit(field@` buff@` "="@` 3);
for (i = 0; i < num; ++i)
puts(field[i]);
}
return 0;
}
0009忘却の名無しさん
NGNG記憶あやふや。
VBにはあったんだよね。
0010デフォルトの名無しさん
NGNGなかったはず
0011名無しさん@お腹いっぱい。
NGNG一応、こうすれば上手く動いてるように見えますが
代入をstrcpyにするとエラーになります・・。
一つ正しい方法を教えてください。
#include <stdio.h>
#include <string.h>
char ** split_num(char * str@`int n);
char ** split_num(char * str@`int n)
{
char *value[256];
char delimita[2]="=";
char * tok;
int value_num = 0;
tok = strtok(str@`delimita);
while(tok != NULL){
value[value_num]=tok;
tok = strtok(NULL@`delimita);
value_num++;
}
return value;
}
int main()
{
char temp[256]="ab=cd=def";
char **p;
p=split_num(temp@`3);
printf("%s"@`p[1]);
return 0;
}
0012名無しさん@お腹いっぱい。
NGNGメモリを確保してないポインターにコピーすりゃ普通落ちるでしょ。
00138
NGNGVBも6からとかじゃなかったかな。
まあ何にせよ、見ての通り実際には別に関数化する程でも無いから、
直接strtokを使用するCプログラマがほとんどだと思う。
なおFreeBSDには、少なくともstrtokよりはマシなstrsepという関数が
あって、これは連続するデリミタを別々のものと扱う(間に空文字列が
入っているものとする)。ただし勿論マルチバイト文字には対応していない。
俺はこの手の仕事が必要な場合は、strsepを下敷きにした関数を使うことが
多い。
001411
NGNGいえ、それはわかってるんですが、やりかたがわからないんです。
具体的なコードでご教授いただければ幸いです。
というか11のコードは正しいんですか?(とてもそうは思えないですが。)
00158
NGNG勿論autoの配列であるvalueへのポインタを返している以上
正しくは無い。valueに対してポインタを代入するだけで済ませるのは、
間違いではない。いずれにせよ、元のstrは壊される。これを良しと
するかどうかは単にポリシー/仕様の問題だ。
どうしてもコピーを生成することに固執するのなら、次のように
するのだね。ただしこれは8のものに比べて非常に非効率で、
しかも後でメモリを解放しなければならない。
strdupは標準の関数では無いが、たぶんついているだろう。
char **split_num(const char *s@` int n)
{
int i = 0;
char *tok;
char *w = strdup(s);
char **field = malloc((n+1) * sizeof(char*));
for (tok = strtok(w@` "="); (i < n) && tok; tok = strrok(NULL@` "="))
field[i++] = strdup(tok);
field[i] = NULL;
free(w);
return field;
}
001611
NGNG>>15
なるほど、勉強になります。
strdupはbcc5.5にもついてました。
8のコードも検討してみます。
ちなみに私は1さんではありません。
0017名無しさん@お腹いっぱい。
NGNGこれで完璧!
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#define LIST_INC 20
typedef struct
{
char** tok;
int num;
int list_max;
} TOK_STRUCT;
void split_num_add(TOK_STRUCT* tok_struct @` char* tok) // 追加
{
int length;
char** new_tok;
length = strlen(tok);
if(length > 0)
{
if(tok_struct->num >= tok_struct->list_max)
{
new_tok = (char**)malloc((tok_struct->list_max+LIST_INC)*sizeof(char*));
if(tok_struct->tok != NULL)
{
memcpy(new_tok @` tok_struct->tok @` tok_struct->list_max*sizeof(char*));
free(tok_struct->tok);
}
tok_struct->tok = new_tok;
tok_struct->list_max += LIST_INC;
}
tok_struct->tok[tok_struct->num] = (char*)malloc(length+1);
strcpy(tok_struct->tok[tok_struct->num] @` tok);
tok_struct->num++;
}
}
void split_num_cleanUp(TOK_STRUCT* tok_struct) // メモリ破棄
{
int i;
if(tok_struct->tok != NULL)
{
for(i=0 ; i<tok_struct->num ; i++) free(tok_struct->tok[i]);
free(tok_struct->tok);
}
memset(tok_struct @` 0 @` sizeof(TOK_STRUCT));
}
void split_num(TOK_STRUCT* tok_struct @` char *str @` char* delimita) // 分割
{
char* tok;
tok = strtok(str@`delimita);
while(tok != NULL)
{
split_num_add(tok_struct @` tok);
tok = strtok(NULL @` delimita);
}
}
int main()
{
char temp[256]="ab=cd=def";
TOK_STRUCT tok_struct;
int i;
memset(&tok_struct @` 0 @` sizeof(TOK_STRUCT));
split_num(&tok_struct @` temp @` "=");
for(i=0 ; i<tok_struct.num ; i++) printf("%s\n" @` tok_struct.tok[i]);
split_num_cleanUp(&tok_struct);
return 0;
}
001811
NGNG全然わからないけど、とりあえずスゴイ・・。
トークンの処理にこれだけやらないと完璧とは言えないのですか・・。
なんか頭がクラクラしてきました。
ありがたく保存させてもらって寝ます。おやすみなさい・・。
(ゴミレスなのでsageさせてもらいます。)
0019デフォルトの名無しさん
NGNGあんだけの行数割いて、結局strtok使うのか。(藁
それと空白や引用符とかどうすんの?
スタック領域のみでmainのargc@`argv互換のでも作った方が後々良いよ。
インターフェースはこれだけ。
int /* <- argc */
getarg(char **argv@` int argvn@` char *argbuf@` const char *str@` const char *dlm);
0020デフォルトの名無しさん
NGNGSTL使え。
STLの凄さを理解してない奴って多いよな・・・
#include <stdio.h>
#include <string.h>
#include <vector>
typedef std::vector<char*> TokType;
void split_num(TokType* toks@` char *str @` char* delimiter) // 分割
{
char* tok;
tok = strtok(str@`delimiter);
while(tok != NULL)
{
toks->push_back(tok);
tok = strtok(NULL @` delimiter);
}
}
int main()
{
char temp[256]="ab=cd=def";
TokType toks;
int i;
split_num(&toks @` temp @` "=");
for(i=0 ; i<toks.size() ; i++) printf("%s\n" @` toks[i]);
return 0;
}
002119
NGNGint /* <-argc */
split_num(char **argv@` int argvn@` char *str@` char* delimiter) {
char* tok = strtok(str@` delimiter);
int ac = 0;
av[ac] = 0;
while (tok && ac < argvn - 1) {
av[ac++] = tok;
av[ac] = 0;
tok = strtok(NULL @` delimiter);
}
}
int main() {
char temp[256]="ab=cd=def";
{
char *av[128];
int i@` ac = split_num(av@` sizeof(av)/sizeof(av[0])@` "=");
for(i=0 ; i<ac ; i++) printf("%s\n" @` toks[i]);
return 0;
}
002219
NGNG0023デフォルトの名無しさん
NGNGスタック領域にこだわる理由は?
002419
NGNG21は20真似してstrtok使ってるから、もはやどうでも良いけど、スレッドセーフと効率優先。
それから、split_numの最後に書き忘れたけど、 return ac; 付けといてね。
002517
NGNG>それと空白や引用符とかどうすんの?
意味分からんぞ!
>>20
STLってなんだ?
見た所JavaのVectorクラスと同じようだが確保したメモリは破棄しなくていいのか?
Vector内部でリスト用のメモリ使ってないのか?
それとも不用になったら自動的に破棄されるとか?
0026デフォルトの名無しさん
NGNG自動的に破棄されるし、メモリの確保なんかも自動でやるぞ。
002719
NGNGchar temp[256]=" \"ab\" = 'cd' = def";
こういう場合どうすんだ?って事。
それから、20のは本質的に21としてる事は変わらんのであれで良い。
わかりやすく言うと、TokTypeは(char *)を保持してるの。
002817
NGNGそうなんだ。
STLって凄いな。
てっきりバグだと思ってツッコミいれたのに・・・
002917
NGNG>char temp[256]=" \"ab\" = 'cd' = def";
全然意味分からん。
今コンパイルしてみたが、
"ab"
'cd'
def
って表示されたが何か問題でも?
0031デフォルトの名無しさん
NGNG1の質問が学校の宿題だったら多分まずいだろ。
0032忘却の名無しさん
NGNG0033デフォルトの名無しさん
NGNGは8と何が違うのかわからんな。
003419
NGNG全然見てなかったよ、すまそ。
0035デフォルトの名無しさん
NGNG標準関数や標準クラスを知らないで仕事をしているなんて信じられませんよ。
しかしサンプルはこうでしょう。
class split
{
private:
vector<string> m_token;
public:
split(const string &s@` const string &d);
split(const split &); //省略
split &operator=(const split &); //省略
string operator[](int i) const { return m_token[i];}
int size() const { return m_token.size(); }
};
split::split(const string &s@` const string &d)
{
auto_ptr<char> w(new char[s.size()+1]);
strcpy(w.get()@` s.c_str());
for (char *token = strtok(w.get()@` d.c_str()); token; token = strtok(NULL@` d.c_str()))
m_token.push_back(string(token));
}
int main(int argc@` char* argv[])
{
split temp("ab=cd=def"@` "=");
for (int i = 0; i < temp.size(); i++)
cout << temp[i];
return 0;
}
なに? C言語? 聞こえんなぁ。
0036デフォルトの名無しさん
NGNG>なに? C言語? 聞こえんなぁ。
残念ながらstrtokは「C言語」の関数ですが。
しかも使用をあまり推薦されてない中での筆頭(笑
それにしてもなんでstrtokのサンプルばっかり?
0037!35
NGNGじゃあ、こんなのはどうだ?
std::stringに対して使えるstrtok関数もどきだ。
string GetToken(string& line@` const char* delims)
{
&nbsp;&nbsp;&nbsp;string ret;
&nbsp;&nbsp;&nbsp;string::size_type index = line.find_first_of(delims);
&nbsp;&nbsp;&nbsp;if(index == string::npos){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret = line;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;line = "";
&nbsp;&nbsp;&nbsp;}else{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret = line.substr(0@` index);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;line = line.substr(index + 1);
&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;return ret;
}
string GetToken(string& line@` char delim)
{
&nbsp;&nbsp;&nbsp;string ret;
&nbsp;&nbsp;&nbsp;string::size_type index = line.find(delim);
&nbsp;&nbsp;&nbsp;if(index == string::npos){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret = line;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;line = "";
&nbsp;&nbsp;&nbsp;}else{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret = line.substr(0@` index);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;line = line.substr(index + 1);
&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;return ret;
}
■ このスレッドは過去ログ倉庫に格納されています