
va_argを使う方法は知っているのですが、受け渡す引数の数を指定しない方法で、決まった型引数を任意数渡す方法はC言語(C++ではない)で実現できますか?
char* test( n, str1, str2, str3, …任意数)
nはint, str○ は const char*
という形ならば、第二引数以降の引数を呼び出し元で n に与えてやれば、n回だけ va_arg(args, char*) を呼び出せばよいですが、
char* test2(str1, str2, str3, str4, …1つ以上の任意数)
という形だと、引数の個数を取得できないためうまくできません。
実現不可能でしょうか?
No.7ベストアンサー
- 回答日時:
実引数の個数を指定せず、かつ終端のNULLも渡さずに、(C++ではなく)C言語で実現ということであれば、次のような方法が考えられます。
char* test(const char*, ...);
#define test(...) test(__VA_ARGS__, NULL);
これで、
test("abc", "def", "ghi");
のように指定するだけで、(見かけ上)終端のNULLを省略してもNULLが勝手に渡されます。
ただし、C99対応のコンパイラでなければ、使えないのが難点です。
No.6
- 回答日時:
>NULLが入るのかなって思っていたのですが、NULLが入らないようなのです。
そうですね。NULLになることを期待しているプログラムです。
bcc32(ボーランドCコンパイラ)では、動作したのですが、他のコンパイラでは、動作しないのですね。
va_argで、変数の要素がなくなったことを感知できないとすると、最後の変数にNULLを渡してやるなどの必要があると思います。(元の形ではできない?)
No.5
- 回答日時:
サンプルを作ってみました。
一番初めの文字列は、連結後のサイズがはいるだけのサイズが必要です。
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
char *strscat(char *s, ...){
char *wk,*ret=s;
va_list ap;
va_start(ap, s);
while(wk=va_arg(ap, char *)){
s += strlen(s);
strcpy(s, wk);
}
va_end(ap);
return ret;
}
void main(void){
char buff[80]="STR1";
char *str2="str2";
char *str3="String3";
printf("%s\n",strscat(buff,str2,str3));
}
この回答への補足
エラーの補足です。
ループ内のstrcpy部分をコメントアウトした結果、
私の環境ではループを2回で終わらなければいけないところを、24回くりかえしていました。
ありがとうございます。
while(wk=va_arg(ap, char *)){
というループをはじめ書いたときにも考えたのですが、どうも引数がもう無いところで、
va_arg(ap, char *)
をすると、NULLが入るのかなって思っていたのですが、NULLが入らないようなのです。
それで得られたポインタ wk を参照するとエラーが起きます。
実際、参考にいただいたソースを実行してみましたが、異常終了します(VC++ 6.0で試しました。 gccではまだ試していません)
No.4
- 回答日時:
exec みたいに最後の引数を (const char *)0 にするという約束にすれば, こんな感じかなぁ?
#include <stdarg.h>
#include <string.h>
char *cloneCat(const char *str1, ...)
{
char *p;
const char *str;
size_t len;
va_list ap;
va_start(ap, str1);
len = strlen(str1)+1;
p = malloc(len);
strcpy(p, str1);
while ((str = va_arg(const char *)) != 0) {
char *q;
len += strlen(str);
q = malloc(len);
sprintf(q, "%s%s", p, str);
free(p);
p = q;
}
va_end(ap);
return p;
}
No.3
- 回答日時:
ポインタを使えばいいのではないでしょうか。
渡したいのが「任意個数のchar *」だとしたら、
char * test(char **str)
もしくは
char * test(char *str[])
として、
関数内で
char *s;
s = str[n];
のようにすればn番目の文字列を取得できます。
呼び出し側が責任を持って、
配列に正しいデータをセットしておかなくてはなりません。
渡すデータを終わりにしたいときは、
NULLポインタ、もしくは予め決めた特定の値を
終わりの印にすればいいでしょう。
でもva_argの使い方をわかってる人に
「ポインタを使え」というのも釈迦に説法という気がします。
これでだめな場合、
どういう要求があるのかをもう少し詳しく説明してください。
この回答への補足
第一引数の・・・
↓
str1の・・・
でした。それとあらかじめ配列にいれる方法も考えましたが、perlの「.」演算子のような感じで使いたいので、
どうしても可変引数にこだわっています^^;
(perlでは
$a = "aaa" . "bbb" . "ccc"
で、連結した文字列が、変数$aに代入される)
すみません、補足いたします。
自前でstrcatに似た文字連結関数を作っています。引数に与えられた文字列を全て連結し、その文字列へのポインタを返すというものです。
とりあえず動作している、「引数の数を渡して処理する方の関数」をのせておきます
char *cloneCat(int n, const char* str1, ...){
const char* *ps;
char *pstr;
ps = &str1; // 第一引数のポインタ取得
//str1の文字列文のメモリ領域取得
if((pstr = (char *)malloc(strlen(str1) + 1)) == NULL)
return NULL;
strcpy(pstr, str1); //第一引数をコピー
for(i=1;i<n;i++){
//メモリサイズ変更。 ++ps 部分で次の引数
//へポインタを進めて、参照し、そのサイズ
//をstrlenで取得
if((pstr = (char *)realloc(pstr, strlen(pstr) + strlen(*++ps) + 1)) == NULL)
return NULL;
//文字連結
strcat(pstr, *ps);
}
//parrayはmallocで得たアドレスを格納している
//大域変数。pcntはその数を入れている大域変数
return parray[pcnt++] = pstr;
}
例えば、pstr = cloneCat(3, "aa", "bb", "cc") とすればpstrには "aabbcc"が得られます。この引数の数3を使わないで関数を実装したいなって思っています。
No.2
- 回答日時:
この回答への補足
読ませていただきました。
最後に目印となるものを置くことで実現するということですね。 思いつきませんでした。
ただ、やっぱりこれでも無駄な引数が1つ増えちゃいますよね。しかし、引数の数を書くよりはずっと楽なので、もし他に方法がみつからなければこちらで実装してみます。
間違っていたらごめんなさい。
No.1
- 回答日時:
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
- C言語・C++・C# const char** p;のとき、free(p)でC4090エラーとなるのはなぜですか 3 2023/03/31 16:28
- C言語・C++・C# c言語 コマンドライン引数 4 2023/02/09 18:47
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# Cの関数の引数のconst *charについて 5 2023/04/25 13:05
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# C言語 共用体について コマンドライン引数で値を2つ入力したときに、argv[2]の値をUNI u1 4 2022/04/25 20:34
- C言語・C++・C# C言語について コマンドラインで >変数 12.00 (char型) と、小数点付きの値を共用体に渡 1 2022/04/22 16:56
- Visual Basic(VBA) VBAでfunctionを利用しようとしたときに「引数は省略できません」というエラーが出ます 1 2022/10/15 16:30
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
CStringからchar*への型変換に...
-
char*を初期化したいのですが
-
C言語のintとcharの違いってな...
-
char型にint型の数値を代入する。
-
C言語にて構造体のメンバがNULL...
-
fgetc( )の戻り値はなぜ整数??
-
char 文字列型 の表現範囲が-12...
-
fgetsで読み込んだ値のvector処理
-
2次元配列の文字"列"の初期化方法
-
C++17で、unsigned char * 配列...
-
Cの関数の引数のconst *charに...
-
wsprintf( ポインタ , "%d" , "...
-
バイト型データの参照
-
警告
-
構造体のメンバーの静的なサイ...
-
char AA[]{"全角文字"};から"全...
-
構造体・ビットフィールドのvol...
-
new charとnew char[N]の違いは?
-
SubStringの使い方について
-
ポインタとcharについて
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
CStringからchar*への型変換に...
-
char*を初期化したいのですが
-
C言語にて構造体のメンバがNULL...
-
C言語のintとcharの違いってな...
-
DWORDとcharの変換
-
C++17で、unsigned char * 配列...
-
char 文字列型 の表現範囲が-12...
-
new charとnew char[N]の違いは?
-
char型にint型の数値を代入する。
-
動的メモリの初期化方法について。
-
小数点入りの文字列をfloat型に...
-
文字型配列に格納した空白の切捨て
-
fstream型オブジェクトを関数の...
-
C++Builder 2009 テキスト...
-
文字列の途中から途中までを抽出
-
C言語の文字リテラル中の16進文...
-
エクセルのMID関数は、C言語では?
-
文字列のswap
-
void型へのポインタ
-
VC++ char[10]へのCString値の代入
おすすめ情報