CでCGIを書く上で、perlのsplit命令の代替になるようなライブラリを探しています。
www=xxx&yyy=zzz という引数をchar型の配列に入れ、それを & で分割し、次に = で分割して

query[0].name = www; query[0].value = xxx
query[1].name = yyy; query[1].value = zzz

などと、perlと同等のことをさせたいのですが、文字列をその都度走査していたのでは処理が莫大になりそうなので、もしご存知であれば教えていただければと思います。

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

A 回答 (1件)

strtokがありますが、結局自分で少しは書かなくてはいけないと思います。


ちょっとCで書いてみました。関数化すればよいと思います。

struct QUERY {
char *name;
char *value;
};

void XXX()
{
char *kari = "www=xxx&yyy=zzz";
char qbuf[128];
strcpy(qbuf, kari);

struct QUERY *query;
char *p;
int count = 1;

for (p = qbuf; *p != '\0'; p ++) {
if (*p == '&')
count ++;
}

query = (struct QUERY *)malloc(sizeof(struct QUERY) * count);

count = 0;
query[0].name = qbuf;
for (p = qbuf; *p != '\0'; p ++) {
if (*p == '=') {
*p = '\0';
query[count].value = p + 1;
} else if (*p == '&') {
*p = '\0';
count ++;
query[count].name = p + 1;
}
}

free(query);
}
    • good
    • 0
この回答へのお礼

ポインタを受け付けない硬い頭によく効きました。
無事に動作して、関数化、組み込みができました。ありがとうございます。

お礼日時:2001/07/25 12:34

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

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

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

Qchar *name1[4] とchar name2[][4] の違いについて

C言語のことで質問があります。

char *name1[4]は
char *name1[4] = {"abcdefghi","jkl","l","mn"};
と宣言でき,ポインタを4つ確保した形となりました。

char name2[][4]は
char name2[][4] = {"abc","def","ghi","jkl","mno","pqr","stu","vwx"};
と4文字以内の文字列を初期化した数だけ確保した形となりました。

この結果からchar *name1[4]の意味は,char name2[][4]ではなくchar name2[4][]に近いと思いました。
しかし,char name2[4][]ではポインタを4つ確保した事にはならないみたいでコンパイルが通りません。
*name1[4]では4つのポインタを確保できるのに~と思ってしまいます。

ポインタと配列は別物と考えるべきなのでしょうか?
訳の分からない質問かもしれませんが,
何卒ご指導いただくようよろしくお願いします。

Aベストアンサー

ポインタと配列の違いというのは、変数と定数の違いのようなものです。

話を簡単にするために、一次元配列から考えましょう。

char *p1; と定義した時のp1は、いうまでもなくポインタで、
これは変数です。p1は任意の文字列を指すことができます。
char a1[4]; と配列の形で定義した場合のa1については、
a1[0]やa1[1]等を、通常のchar型の変数と全く同じように扱うことが
できます。しかし、a1自体は、例えば a1 = p1; のように値を代入する
ことができません。(逆の p1 = a1; は可能。)つまり、この場合のa1は、
変数ではなく、定数のようなものなのです。

複合的なケースについて見てみましょう。
char **q1; ポインタへのポインタ
 q1,*q1,**q1,q1[0],*q1[0],q1[0][0] のいずれも変数として
 扱うことができます。(値を代入することが文法的に許されます。
 ただし、実行時にはアクセス違反になる場合もあります。)
char q2[4][4]; 二次元配列
 q2,q2[0]は変数として扱うことができません。q2[0][0]のように
 して、初めて変数として扱えるようになります。
char *q3[4]; ポインタの配列
 q3は変数として扱うことができませんが、q3[0],*q3[0],q3[0][0]
 はいずれも変数として扱うことができます。
 なお、この定義は char *(q3[4]); とした場合と全く同じ意味です。
char (*q4)[4]; 配列へのポインタ
 q4,(*q4)[0],q4[0][0]はいずれも変数として扱うことができます。
 しかし、*q4,q4[0]は変数として扱うことができません。

char *name1[4]; と char name2[4][]; は確かに似ています。しかし
違うところもあります。それは、name1[0] が変数として扱えるのに
対し、name2[0] には値を代入できないという点です。(データの
具体的な構造については、inthefloiさんが書いておられる通りです。
> char name2[4][]ではポインタを4つ確保した事にはならないみたい
というのも、全くその通りで、配列の定義では、ポインタ変数の領域
を確保する余地はないのです。

ポインタと配列の違いというのは、変数と定数の違いのようなものです。

話を簡単にするために、一次元配列から考えましょう。

char *p1; と定義した時のp1は、いうまでもなくポインタで、
これは変数です。p1は任意の文字列を指すことができます。
char a1[4]; と配列の形で定義した場合のa1については、
a1[0]やa1[1]等を、通常のchar型の変数と全く同じように扱うことが
できます。しかし、a1自体は、例えば a1 = p1; のように値を代入する
ことができません。(逆の p1 = a1; は可能。)つまり...続きを読む

Q[C#] string name = new ..

こんにちは。

string name;
name = "sukeken";

これを、オブジェクト指向プログラミングらしく

string name = new string("sukeken");

とするのは、ダメなのでしょうか?
コンパイルは、許してくれないようなのですが…。

同じように、intもダメでしょうか?

環境 VisualStudio2012 C#

よろしくお願いいたします。

Aベストアンサー

C#では文字列そのものがstring型のオブジェクトなので、stringのコンストラクタにstringを指定するというのは完全に無駄なので、コンストラクタが用意されていないのだと思います。

どうしてもそのように書きたいのであれば、たとえば

string name = new string("sukeken".ToCharArray());

と書くことは出来ますが、stringをいったんcharの配列に変換してstringにする、という非常に無駄な処理になります。

単純に

string name = "sukeken";

がベストです。

Q構造体でchar name[]と*nameの違い

char name[20]と*nameの違いがまだハッキリわかりません
sizeof()で調べたら*nameの方で実行した構造体のプログラムはname[20]で実行したのに比べてバイト数なども半分になり、アドレスの間隔も変化したので、ポインタで定義したほうが良いような感じはするのですがこんな単純な理由ではないと思います。

この2種の違いがインターネットを調べても納得いく答えがだせず、教科書にも詳しく書かれていなかったので、分かる方がおられれば教えてください。



作成中のプログラムです
#include<stdio.h>
structmdcl_chk{
//charname[20];
char*name;
intage;
floatweight;
floatheight;
};

void main(void)
{
inti,x;
structmdcl_chkMdcl_Chk[5]={
{"タカノハナ ",38,150.0,183.0},
{"ワカノハナ ",39,120.0,180.0},
{"ムサシマル ",39,237.0,192.0},
{"アサショウリュウ",30,147.0,184.0},
{"ハクホウ ",25,149.0,192.0}
},*MC,*DEF,*OFF;



MC=Mdcl_Chk;

for(i=0;i<5;i++){
printf("%s %d %5.1f %5.1f\n",( MC+i )->name,( MC+i )->age,( MC+i )->weight,( MC+i )->height);
}

printf("\n");
printf("Mdcl_Chk = %3d bite\n",sizeof(Mdcl_Chk));
printf("mdcl_chk = %3d bite\n",sizeof(mdcl_chk));
printf(" MC = %3d bite\n",sizeof(MC));
//アドレス表示
MC=Mdcl_Chk;
printf("\n");
for(i=0;i<5;i++){
printf("Mdcl_Chk[%d] adr = %08d %08X\n",i,MC+i,&Mdcl_Chk[i]);

}

}

char name[20]と*nameの違いがまだハッキリわかりません
sizeof()で調べたら*nameの方で実行した構造体のプログラムはname[20]で実行したのに比べてバイト数なども半分になり、アドレスの間隔も変化したので、ポインタで定義したほうが良いような感じはするのですがこんな単純な理由ではないと思います。

この2種の違いがインターネットを調べても納得いく答えがだせず、教科書にも詳しく書かれていなかったので、分かる方がおられれば教えてください。



作成中のプログラムです
#include<stdio.h>
structmdcl...続きを読む

Aベストアンサー

>char name[20]と*nameの違いがまだハッキリわかりません

char []は配列です。
指定されたサイズのメモリがあることは保証されます。
# 変数の寿命については考慮する必要がありますが。

char *はchar型の領域を指すポインタです。
# ポインタ変数の領域として、32BitOS上のソフトであれば一般的に4バイト必要です。

ポインタ変数は有効などこかの領域を指している必要があります。
たいていのローカル変数は初期化されていませんので、正しい領域を指しません。
掲示されている例の場合、ポインタは文字列リラテルを指しているので問題ありませんが…
文字列リラテルを指していますので、内容を書き換える事はできません。
strcpy(Mdcl_Chk[1].name, "ホクトウミ");
というようなコトはできません。
# 代わりに Mdcl_Chk[1].name = "ホクトウミ"; は可能。
# C言語の文字列処理の経験が浅いと、こっちの方が便利に見えるかも知れませんけどね…。

掲示の場合は変数宣言時に初期値が設定されているので問題ありませんが…
配列Mdcl_Chkが未初期化の場合に外部からデータを読み込む時に問題になるでしょう。
char name[20];
の場合は、文字列終端の'\0'込みで20バイト確保されています。
char *name;
の場合は動的メモリ確保(malloc()など)で正しい場所を指すようにしないとアクセス違反になります。
# 動的確保したら不要になった時点で自分で開放する必要があります。
# 動的確保の為、確保できるメモリ容量以外に文字数を制限する要素はありません。
# 勿論、メモリ確保に失敗する可能性も考慮する必要がありますが。

>この2種の違いがインターネットを調べても納得いく答えがだせず

どう納得ができない…のでしょう?

>char name[20]と*nameの違いがまだハッキリわかりません

char []は配列です。
指定されたサイズのメモリがあることは保証されます。
# 変数の寿命については考慮する必要がありますが。

char *はchar型の領域を指すポインタです。
# ポインタ変数の領域として、32BitOS上のソフトであれば一般的に4バイト必要です。

ポインタ変数は有効などこかの領域を指している必要があります。
たいていのローカル変数は初期化されていませんので、正しい領域を指しません。
掲示されている例の場合、ポインタは文字列リラ...続きを読む

Qname[3] = seq + '0';の意味

オライリーC実践プログラミングのP203、例13-11の例で質問です。
このプログラムでは一時的なファイル名を返す関数、tmp_nameがあるのですが
このプログラム中の以下の行がよく分かりません。
name[3] = sequence + '0';

直感的にsequenceだけでよさそうな気がするのですが以下のように書き直すと
出力結果にsequenceの数字がでずただ"tmp"と出力されるだけでした。
name[3] = sequence;


char型にint型を使うための手段なのでしょうか?
下記にプログラム全体を載せておきます。よろしくお願いします。

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

char *tmp_name(void)
{
static char name[30];
static int sequence = 0;

++sequence;

strcpy(name, "tmp");

name[3] = sequence + '0';
name[4] = '\0';

return (name);

}

int main()
{
char *tmp_name(void);

printf("%s\n", tmp_name());

return (0);
}

オライリーC実践プログラミングのP203、例13-11の例で質問です。
このプログラムでは一時的なファイル名を返す関数、tmp_nameがあるのですが
このプログラム中の以下の行がよく分かりません。
name[3] = sequence + '0';

直感的にsequenceだけでよさそうな気がするのですが以下のように書き直すと
出力結果にsequenceの数字がでずただ"tmp"と出力されるだけでした。
name[3] = sequence;


char型にint型を使うための手段なのでしょうか?
下記にプログラム全体を載せておきます。よろしくお願いします。

#incl...続きを読む

Aベストアンサー

これは、0から9までの数値をそれに対応する文字に変換するお手軽かつ問題のある手法です。

ご存知かもしれませんが、コンピューターでは文字は内部的には対応する数値で表されています。
ですから、C/C++ではchar形の中にあるのは文字ではなくその文字に対応する数値です。
したがって、
sequence + '0'
は0という文字を表す数値にsequenceを足した値になります。文字と数値の対応はたいてい0という文字の次に1, 2, ..., 9と続くようになっていますので、結果、sequenceが0なら0という文字を表す数値、sequenceが1なら1という文字を表す数値、…という値になります。
参考キーワードとして「ASCIIコード」を調べるといいでしょう。

数値から文字への変換がたった1回の足し算で出来る、とってもお手軽な方法ですよね?

でも、以下のように問題があるのであまり使わないほうがいい方法です。

・0から9までしか使えない
上で書いたとおり、この方法でsequenceが0なら0という文字に、1なら1という文字に変換できます。……では、sequenceが-1だったら?10だったら?

・そもそも前提に疑問が残る
文字と数値の対応はたいてい0という文字の次に1, 2, ..., 9と続くようになっています。……でもあなたの処理系で本当に連続して並んでいますか?将来そのように並んでない処理系への移植がないと100%言い切れますか?

これは、0から9までの数値をそれに対応する文字に変換するお手軽かつ問題のある手法です。

ご存知かもしれませんが、コンピューターでは文字は内部的には対応する数値で表されています。
ですから、C/C++ではchar形の中にあるのは文字ではなくその文字に対応する数値です。
したがって、
sequence + '0'
は0という文字を表す数値にsequenceを足した値になります。文字と数値の対応はたいてい0という文字の次に1, 2, ..., 9と続くようになっていますので、結果、sequenceが0なら0という文字を表す数値、sequenceが...続きを読む

Qfp = fopen(argy[1], "r");の[1]の意味は

https://oshiete.goo.ne.jp/qa/8940272.html
 の11行目に
fp = fopen(argv[1], "r");の[1]の意味が分かりません。
試したいのですが、ソフトがうまく動きません
 よろしくお願いいたします。

Aベストアンサー

前の例題も読みました。

大分苦戦しているようですが、配列については理解が進みましたでしょうか?
お答えしますと、最初のパラメータ文字列が代入されています。

古いC言語の約束でして大変有名なものです。

コマンドラインコンソールから実行ファイル名を書いて、
パラメータをスペースで区切って指定したとします。

このパラメータ文字列が[1]以降に入ります。
例として、"test"と言う名前の実行ファイルがあったとします。

例)> test test1 test2 3 4

このようにコマンドラインから入力し実行すると、

argc = 5
argv[0] = "test"
argv[1] = "test1"
argv[2] = "test2"
argv[3] = "3"
argv[4] = "4"

と文字列が入ってきます。

以下はサンプル。

void main( int argc , char *argv[])
{
if( argc < 2 )
{
// パラメータ指定がなかった場合の表示
printf( "test に続けて4つまでパラメータを入力できます\n");
exit(0);
}
if( argc > 5 )
{
 // パラメータが5つ以上あった場合の表示
printf( "5つ以上のパラメータは受け付けません\n");
exit(-1);
}

// 正常ルート
printf( "パラメータの数は%d個ですね?ニヤッ\n", argc-1);
printf( "最初のパラメータは%sでしょ?\n", argv[1]);
printf( "残りはargv[2]以降ですが、面倒なので表示しません\n");
}

と言う具合に、引数を活用できます。argv[0]には、実行ファイル名が入ります。
argc は実行ファイルの名前も含めてカウントされます。

プログラムによっては必要な引数の数が変わりますし、
ユーザーのコマンドラインからの入力ミスなどでパラメータがなかったり、
必要なパラメータが不足していたりしますので、
argcとargvを使って最初にシンタックスエラーチェックをするのが常道です。

実行ファイル名の指定がなく、プログラムが実行されることはないと思われます
から、argcは1以上の値になります。

argc, argvの活用は、
実行コマンドを手打ちで打ち込むコンソール形式でよく用いられる基本的な
アプリケーションの開発手法です。

ご質問の箇所は、
第一パラメータにプログラム内で読み込むファイルのファイル名を指定してるの
でしょう。(よくあります)

しかし、Windowsなどのウィンドウを使用するアプリケーションは、
これとは違っておりますので注意が必要です。
(C言語とは別に、Windowsに特化した開発ノウハウの勉強が必要です)

Windows系で上記の様な基本的なプログラムを作成する場合は、
プロジェクトの作成時に(VisualStudioなどで)コンソールアプリケーション
を選んで作成します。実行時にコンソールが開きます。

Linuxの場合は、コンソールがデフォルトになっているでしょうから、
(特殊な設定がなければ)そのまま作成できます。

テキストエディタでソースを記述し、gcc などでコンパイルします。
実行形式ファイルが出来ていれば、想定どおりの動作をするでしょう。

ファイルの読み込みが出来るようになったら、
ファイルの内容を書き換えて保存したり、
ファイル名を変えたり、
ディレクトリ内のファイルを全て表示したり、
ファイル内に含まれる文字列を検索し、該当するファイルをリストしたりなど、

有用なサンプルプログラムを沢山作って練習します。

ファイルを読み込む先は、char型の配列でバイトサイズのメモリーとして確保
します。メモリーと変数の関係を充分に理解することをお勧めします。
殆どのプログラムは、このメモリーの確保やメモリーサイズの計算と格闘する
場合が多くなるからです。

バイナリー形式のファイル(すべてはバイナリー形式として良いのですが)に
ついて理解が深まった後は、
bmpの画像ファイル、wavなどの音声ファイルをあけて、
これの中身を書き換えて遊びます。

特にwavファイルは、音量の変更や周波数フィルタなども掛けれますので、
メモリ、配列、ファイルの関係を(焦らずに)ゆっくり理解するだけで、
今の知識レベルでも面白いことが沢山出来ます。

以上、ご参考に成れば。

前の例題も読みました。

大分苦戦しているようですが、配列については理解が進みましたでしょうか?
お答えしますと、最初のパラメータ文字列が代入されています。

古いC言語の約束でして大変有名なものです。

コマンドラインコンソールから実行ファイル名を書いて、
パラメータをスペースで区切って指定したとします。

このパラメータ文字列が[1]以降に入ります。
例として、"test"と言う名前の実行ファイルがあったとします。

例)> test test1 test2 3 4

このようにコマンドラインから...続きを読む


人気Q&Aランキング

おすすめ情報