C言語において、関数ポインタの型をtypedefで作ると、

typedef int (*MyFunc)(int*,int*);

と宣言でき、関数ポインタの変数は、

int FuncA(int* a, int* b)
{

}

void main_loop()
{
MyFunc pf = FuncA;

(*pf)(pa,pb);
}

というように使うと思います。

ここで疑問なのですが、この実際に呼び出される関数、FuncAの定義に、typedef(ここではMyFunc)を使えないものでしょうか?

同じことを2回やっているようで、無駄に思えてしまいます。

A 回答 (5件)

C では、式の中の関数名だけが関数を指すポインタに読み替えられます。


# これは、コンパイラが勝手に読み替えます。

関数定義やプロトタイプ宣言といった、式の中にない関数名はポインタに読み替えられることはありません。

ですので、ご質問の中にある

> typedef int (*MyFunc)(int*,int*);



> int FuncA(int* a, int* b)
> {
> ~
> }

は、別の型ということになります。

FuncA( pa, pb ); // FuncA はポインタに読み替えられている。

と関数を式の中に記述した場合にのみ、コンパイラがこの FuncA をポインタとして読み替えるんです。

式の中という意味では、以下の場合も同様です。

MyFunc pf = FuncA; // FuncA はポインタに読み替えられている。

実際、pf に FuncA を代入する場合、以下のようにしても正常に動作します。

MyFunc pf = &FuncA; // アドレス演算子 & をつけてみる。

ついでに、(*pf)() コールの箇所も、以下のようにすることができます。

pf(pa,pb); // 間接参照演算子 * をとってみた。

つまり、関数を指すポインタに「限って」いえば、間接参照演算子はあってもなくても良い存在です。
というわけで、こんなことをしてもコンパイルエラーにも実行エラーにもなりません。

(**********pf)(pa,pb); // どうせ * は何もしないし。。。

このように、関数のポインタ周りの仕様はかなり混乱しています。
配列とポインタが違うものであるように、関数と関数ポインタも別物です。
どちらも、C のコンパイラが自分の都合でポインタに読み替えているだけです。

こんな感じでいかがでしょうか。
    • good
    • 0

関数ポインタに代入する関数が、1つで決まってるなら無駄といえば無駄ですね。


この場合なら
int FuncA(int* a, int* b){~}
void main_loop(){
 FuncA(pa,pb);
}
で十分です。

関数ポインタが必要になるような例は。

typedef int (*MyFunc)(int*,int*);
int FuncA(int* a, int* b){ ~ }
int FuncB(int* a, int* b){ ~ }

void main_loop(){
 MyFunc pf;
 if (flag) {
  pf = FuncA; // flagが真であればFuncAを呼び出す
 } else {
  pf = FuncB; // flagが偽であればFuncBを呼び
 }
 (*pf)(pa,pb);
}
こうゆう使い方なら納得できるとかと思います。
    • good
    • 0

多分, できないと思います.


該当する例は見付ていないのですが,
The identifier declared in a function definition (which is the name of the function) shall have a function type, as specified by the declarator portion of the function definition.
とあって, ここに対する脚注として
The intent is that the type category in a function definition cannot be inherited from a typedef.
と書かれており, その例として以下が規格に挙げられています:
typedef int F(void);
F f, g; // f and g both have type compatible with F
F f { /* ... */ } // WRONG: syntax/constraint error
F g() { /* ... */ } // WRONG: declares that g returns a function
脚注部分で「the type category in a function definition cannot be inherited from a typedef」と書かれているので,
typedef int (*PF)(void);
でも
PF *f { /* ... */ }
はアウトだと思います.
    • good
    • 0
この回答へのお礼

こういうものだと思うことにします^^;
ご丁寧にありがとうございました。

お礼日時:2006/06/27 20:59

おそらく参考書を読みながら質問しているのかと思いますが、参考書では関数のポインタを手短に説明するために質問にあるようなコードが提示されているんだろうと思います。



もう少し発展させて・・・
MyFunc pf;
ではなく、単純なリスト構造にするために
MyFunc pf[100];
とかだったら、(配列の終わり判定を含めて)100個までの処理を並べることができますよね。
あとは添え字をインクリメントしていけば、バッチ言語処理のようなことが出来そうな気がしてくれば、C言語のプログラミングを勉強した甲斐があったというものでしょう。

もっと詳しく知りたいのならば、
「実用Cプログラミング生 粋のCプログラマへ」H.シュルト著
http://www.fukkan.com/vote.php3?no=19161
とか
「エキスパートCプログラミング - 知られざるCの深層 -」Peter van der Linden著
などといった、K&Rを卒業した中級以上のスキルを対象にする本を眺めてみることです。
    • good
    • 0

MyFunc pf = FuncA;



代入(メモリ上に値を記憶するための必要な領域を確保)

(*pf)(pa,pb);

演算処理?
    • good
    • 0

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

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

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

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

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

Qエクセルの下記表について答えを導く関数式とは?

 下記のような形式の車種別の生産予定表があるとします。


  A   B  C  D  E  F  G  
1車種 4/1 2  3  4  5  6日  
2車1  20    30 50
3車2     60 80
4車3              40
5車4  50
6車5     40 30   
7車6              70 10台

 のような少ロットで変動の多い生産予定表について
 4月X日の車Xの生産数を知るにはINDEX+MATCH関数、VLOOKUP+MATCH関数で表を縦横に検索すれば交差するセルの台数を返しますが、仮に台数が分かっているとして、逆の論理として
 車1の生産があった日が4月1日、3日、4日であるという生産対象日を返したい。
 4月3日の生産は車1、車2、車5であるという車種名を返したい。

 これを出来るように関数式を考えていますが、上手く答えを出せません。セルに返る戻り値が一つではありません。
一つの関数式では無理なんでしょうか?VBAが分からないので関数で出せると助かるのですが、方法がありましたら、どなたかご教導お願い申し上げます。
 
 
 

 下記のような形式の車種別の生産予定表があるとします。


  A   B  C  D  E  F  G  
1車種 4/1 2  3  4  5  6日  
2車1  20    30 50
3車2     60 80
4車3              40
5車4  50
6車5     40 30   
7車6              70 10台

 のような少ロットで変動の多い生産予定表について
 4月X日の車Xの生産数を知るにはINDEX+MATCH関数、VLOOKUP+MATCH関...続きを読む

Aベストアンサー

既存の関数のみで行う場合、結果は連続した文字列として1個のセルに表示することになります。単純化のため、ご例示のシートをさらにコンパクトにします。カラムが揃わない場合、メモ帳に貼り付けてご覧ください。

*| A|B|C|D|E|
1|  |1|2|3|
2|車1|4|3| |
3|車2|7| | |
4|車3| | |5|
5|

E2に定義
=IF(B2<>"",$B$1&" ","")&IF(C2<>"",$C$1&" ","")&IF(D2<>"",$D$1&" ","")
以下、E4まで下へドラッグ

B5に定義
=IF(B2<>"",$A$2&" ","")&IF(B3<>"",$A$3&" ","")&IF(B4<>"",$A$4&" ","")
以下、D5まで右へドラッグ

結果
*| A|   B|  C|   D|E |
1|  |   1|  2|   3| |
2|車1|   4|  3|    |1 2 |
3|車2|   7|   |   3|1 3 |
4|車3|    |   |   5|3 |
5|  |車1 車2|車1 |車2 車3|  |

実際のシートの縦横の大きさはいかほどでしょうか。「数式バー」で編集可能な文字列の長さには限りがあります。この方法では実用に耐えない場合、VBAマクロでユーザ定義関数を作成しセルでそれを参照するという方法を検討してください。

既存の関数のみで行う場合、結果は連続した文字列として1個のセルに表示することになります。単純化のため、ご例示のシートをさらにコンパクトにします。カラムが揃わない場合、メモ帳に貼り付けてご覧ください。

*| A|B|C|D|E|
1|  |1|2|3|
2|車1|4|3| |
3|車2|7| | |
4|車3| | |5|
5|

E2に定義
=IF(B2<>"",$B$1&" ","")&IF(C2<>"",$C$1&" ","")&IF(D2<>"",$D$1&" ","")
以下、E4まで下へドラッグ

B5に定義
=IF(B2<>"",$A$2&" ","")&IF(B3<>"",$A$3&" ","")&IF(B4...続きを読む

Q関数ポインタを返す関数の型をtypedefする方法

C言語について質問します。

ある関数を定義するとします。
その関数は引数としてintを一つ取り、返値としてその関数と同じ型の関数へのポインタを返すようにしたいのですが、どのように書けばよいのでしょうか?
そして、その関数の型をtypedefで定義したいです。

例えば、FNをtypedefしたいその関数の型だとすると、

typedef FN (*FN)(int);

のようなFNを定義したいのですが、上のように書いても当然コンパイラ(VC9)に怒られます。
最悪、

typedef void* (*FN)(int);

とvoidポインタを返すように定義しておいて、そのポインタを返値として受け取った側でFNにキャストし直す方法で対処できなくもないですが、ちょっと強引過ぎる気がします。
何かいい方法はあるのでしょうか?

boost::functionあたりを使えばできそうな、そうでもないような気がしますが、できれば純粋なCでの解決法を望みます。
よろしくお願いします。

Aベストアンサー

こんばんは。
More Exceptional C++の213~214ページにそっくりそのままの用途の内容がありますね。

まず
typedef FN (*FN)(int);
と言ったこと自体は確かに不可能です。

ということで、これに似た事がやりたい場合はどうするか
という方向性の話ですが


問題なのは
typedef void* (*FN)(int);
この形式では

void*は関数ポインタ以外のポインタ(オブジェクトのポインタ)はどんなものでも保持できる十分な大きさが保証されているが、関数ポインタに対してはその限りではなく

sizeof(void*) < sizeof(FN)

となるプラットフォームも存在するし、別のコンパイラにしたり、バージョンアップするだけで、動作しなくなる可能性がある
とのことです。

そう言う点だけであれば関数ポインタを使ってキャストすれば可能ではある
とは書かれています。

↓以下若干変えつつ引用、その1

/////////////////

typedef void (*VoidFP)();
typedef VoidFP (*FP)();

VoidFP f(){ return (VoidFP)f; } //VoidFPへのキャスト。

FP p = (FP)f; //VoidFPからのキャスト。
p();


このコードは技術的に正しい。

しかし、型システムを故意に破っている点で危険であり、f()の全ユーザにキャストの使用を強制する点で望ましくない。

/////////////////

とのことです。

そしてC++のコードになりますが
「正しく、かつ移植性のある方法」と銘打たれている方法は

若干変えつつ引用、その2
/////////////////

class FP_;
typedef FP_ (*FP)();

class FP_ {
FP p_;
public:
FP_( FP p ) : p_(p){}
operator FP(){ return p_; }
};

これで、FPオブジェクトの宣言、定義、および自然な呼び出しが可能になる。

FP_ f(){ return f; }

int main(){
FP p = f(); //自然な呼び出しのシンタックス
p();
}

/////////////////

とのことですね。

こんばんは。
More Exceptional C++の213~214ページにそっくりそのままの用途の内容がありますね。

まず
typedef FN (*FN)(int);
と言ったこと自体は確かに不可能です。

ということで、これに似た事がやりたい場合はどうするか
という方向性の話ですが


問題なのは
typedef void* (*FN)(int);
この形式では

void*は関数ポインタ以外のポインタ(オブジェクトのポインタ)はどんなものでも保持できる十分な大きさが保証されているが、関数ポインタに対してはその限りではなく

sizeof(void*) < sizeof(FN)

と...続きを読む

Qエクセルの関数にて【今日の日付から3ヶ月後の日付を入力する関数とは?】

3ヶ月ごとに更新する契約書を作成しています。
ある日付からちょうど3ヶ月後の一日前が出るような関数を探しています。

例えば、
セルに今日の日付「9月6日」と入れると、そのとなりのセルには契約の切れる「12月5日」が出るようにしたいのですが、うまい具合に出来ません。

GOOの賢人様方、お知恵をお貸しください!

Aベストアンサー

アドインで分析ツールが組み込まれている場合は

=EDATE(A1,3)-1

そうでない場合は

=DATE(YEAR(A1),MONTH(A1)+3,DAY(A1))-1

ただし、11月30日をA1に入力した場合、答えが3月1日になってしまうようです。
(うるう年であれば2月29日となりOK)

QC言語のtypedefの質問

Cビギナーです。
私のプログラムが長くなるのは、
ファイルの分割をしてないからだと知った今日この頃なのですが、
それを勉強するためにあるホームページを見ていたのですが、
次のようなサンプルプログラムがありました。

/* main.c */
#include <stdio.h>

extern int func(int);
typedef int (*pf)(int);
extern pf getaddress(void);

int main(void)
{
printf("%d\n",(getaddress())(4));
return 0;
}

/* sub.c */
static int func(int c)
{
return c*10;
}

typedef int (*pf)(int);
pf getaddress(void)
{
return func;
}

ここで、typedef int (*pf)(int);の部分が分かりません。
intを(*pf)(int)で置き換えているのでしょうが、
それ自体がどういう意味か分かりません…
どなたか教えて下さい。

Cビギナーです。
私のプログラムが長くなるのは、
ファイルの分割をしてないからだと知った今日この頃なのですが、
それを勉強するためにあるホームページを見ていたのですが、
次のようなサンプルプログラムがありました。

/* main.c */
#include <stdio.h>

extern int func(int);
typedef int (*pf)(int);
extern pf getaddress(void);

int main(void)
{
printf("%d\n",(getaddress())(4));
return 0;
}

/* sub.c */
static int func(int c)
{
return c*10;
}

typede...続きを読む

Aベストアンサー

>pf getaddress(void)
C言語では関数型は返せなくとも、
関数へのポインタ型は戻り値として
指定することが出来ます。
上記で引数無しのint型引数にとるint型を返す関数型への
ポインタを返す関数として認識されます。

関数型はそれ自体がポインタとなります。
しかし、プログラム内(関数内)で書くと引数リストを要求される
処理系もあり、コンパイラによっては「return func;」では
エラーになります。
関数型にアンパサンド(&)をつけて宣言子型派生を行っても、
取得できるポインタ自体は変わることが無いので、
「return &func; 」とするのが正しいと思います。

上記はあくまでも関数内で特定の関数型指定してを返す場合で、
殆どの場合関数ポインタを使う上では最も多く使われるのが、
関数テーブルだと思います。

関数のポインタ自体を返すというのはあまり行いませんが
以下は今回ののような任意の関数ポインタを返すサンプルです。

/* sub.h */
typedef enum{
 TEST1_FUNC,
 TEST2_FUNC,
 TEST3_FUNC,
 MAX_DISPATCH,
}fcode;

typedef int (*pf)(int);

pf getaddress( fcode code );

/* main.c */
#include "sub.h"

int main( void )
{
 pf pfunc;
 pfunc = getaddress( TEST2_FUNC );
 pfunc( 4 );
 return 0;
}



/* sub.c */
#include <stdio.h>

int test1( int num );
int test2( int num );
int test3( int num );

static pf ftable[] =
{
 test1,
 test2,
 test3,
 NULL,
};

pf getaddress( fcode code )
{
 if ( TEST1_FUNC > code ||
   MAX_DISPATCH <= code )
 {
  return NULL;
 }
 return ftable[code];
}

int test1( int num )
{
 return printf("test1 = %d\n", num);
}

int test2( int num )
{
 return printf("test2 = %d\n", num );
}

int test3( int num )
{
 return printf("test3 = %d\n", num );
}
※全角は半角に変換してください

>pf getaddress(void)
C言語では関数型は返せなくとも、
関数へのポインタ型は戻り値として
指定することが出来ます。
上記で引数無しのint型引数にとるint型を返す関数型への
ポインタを返す関数として認識されます。

関数型はそれ自体がポインタとなります。
しかし、プログラム内(関数内)で書くと引数リストを要求される
処理系もあり、コンパイラによっては「return func;」では
エラーになります。
関数型にアンパサンド(&)をつけて宣言子型派生を行っても、
取得できるポインタ自体は変わるこ...続きを読む

QエクセルのSAM関数の「SAM」とは何かの略語なのでしょうか?

エクセルのSAM関数の「SAM」とは何かの略語なのでしょうか?
例えば、MAX関数であれば「MAX」が日本語で「最大値」だと分かります。
「AVERAGE」であれば、「平均」です。
詳しい方がいましたら、宜しくお願い致します。

Aベストアンサー

SUM は、最初、SUMMARY だと私も思っていました。しかし、Summary には、「合計」という意味はなく、要約するという意味です。現在、私自身は、数学用語の、SUMMATION =Σ (総和、合計)という語の省略形だと思っています。

Summation (サメイション) [数学用語]
the total amount or number when two or more things are added together.
[2つまたはそれ以上のものを一緒に加えた時に、その合計値または数値のこと]

ただ、この命名は、Microsoft ともロースタ社とも関係がなく、1970年代の後半、ハーバード大学ビジネススクールの学生、ダンブルックリンらによるもので、彼らはパテントなどの主張も出来ずに、大手の会社に取り入れられてしまい、その時のものが現在まで流用されています。したがって、誰も、その語源に対して主張ができません。

1980年代に、IBMから出ていた表計算の本に、SUM関数の出来た秘話も読んだことがあります。学生さんが、教授が、授業中に何度も黒板を書いたり消したりするのをみて、PCで、できたらと考えたそうです。当時、すでに大型コンピュータには表計算は存在していましたが、PCにはありませんでした。計算範囲の中に、文字列を入れても、エラーを出さずに、合計が出せるという所が、この関数の特徴です。

SUM は、最初、SUMMARY だと私も思っていました。しかし、Summary には、「合計」という意味はなく、要約するという意味です。現在、私自身は、数学用語の、SUMMATION =Σ (総和、合計)という語の省略形だと思っています。

Summation (サメイション) [数学用語]
the total amount or number when two or more things are added together.
[2つまたはそれ以上のものを一緒に加えた時に、その合計値または数値のこと]

ただ、この命名は、Microsoft ともロースタ社とも関係がなく、1970年代の後半、ハーバード大学...続きを読む

QC言語のvoid型ポインタ変数について。

C言語のvoid型ポインタ変数について。

C言語のvoid型ポインタ変数について質問があります。

組み込み系の開発を行っているのですが、現在使用しているシステムで、
提供されている "API" を介してアプリケーション部のソフト作成を行っています。

この "API" ですが、引数の多くはvoid型ポインタとなっています。

ある人がこの引数がvoid型となっているのを見て、
『なんでvoid型なんや??、C言語でアセンブラと違うんやから、void型なんかにしない方が良い』
とおっしゃいました。
この意味がよくわからなかったのですが、なぜ void型はよろしくないんでしょうか?

--
僕が思うに、APIなんやから引数を void型ポインタ にすることでどんな型にも対応できる
汎用的であると感じ、逆にこの方が良いのではと感じたのですが。。


-API例----
int _exApiKannsuu( char in_data, void* out_data )

"in_data" をもとに "out_data" を取得する。
どーやらこの "out_data" が void型 であるのががよくないらしい・・

C言語のvoid型ポインタ変数について。

C言語のvoid型ポインタ変数について質問があります。

組み込み系の開発を行っているのですが、現在使用しているシステムで、
提供されている "API" を介してアプリケーション部のソフト作成を行っています。

この "API" ですが、引数の多くはvoid型ポインタとなっています。

ある人がこの引数がvoid型となっているのを見て、
『なんでvoid型なんや??、C言語でアセンブラと違うんやから、void型なんかにしない方が良い』
とおっしゃいました。
この意味がよ...続きを読む

Aベストアンサー

同じ関数で 複数の型のデータを扱うのでなければ特定の型のポインタにしたほうが良いでしょう

このAPI宣言だけみた使用者は 何型のポインタを渡せば良いのかわかりません

char*で良いのか int*が必要なのかはたまた何かの構造体のポインタを要求しているのか ・・・

Qエクセル関数で使われる10^10とは何でしょうか。

エクセル関数で使われる10^10とは何でしょうか。

他の教えて!gooで書かれていた数式を用いてデータ取得には成功したのですが
関数の内容が知りたいのでわかるかたお願いします。

参考アドレス: http://oshiete.goo.ne.jp/qa/6085476.html
(以下参照文)
----------------------------------------------------------
例えばA1セルからE1000セルの間で数値の入っている下端のデータであれば次のように作業列を設けて求めることができます。
初めに1行目に新たな行を挿入します。
A1セルには次の式を入力してE1セルまでオートフィルドラッグします。

=MATCH(10^10,A2:A1000)+1

----------------------------------------------------------

上記に出てくる10^10は何を表わしているのでしょうか。。
どうぞよろしくお願いいたします。

Aベストアンサー

10^10とは10の10乗で100億です。

=MATCH(10^10,A2:A1000,1)

100億より小さい数字で最大のものを求めるということで、その表で最大値が決まっていれば、それより大きい数字であれば何でもOKです。

ちなみに、MATCH関数で、照合の型に 1又は省略の場合、昇順になっていない場合、検索値より小さいもので、一番下のものの位置を返します。

QC言語 ポインタ型引数の呼び出しについて2

C言語 ポインタ型引数の呼び出しについて2

以前質問した関数ですが、ネットを検索していたら同じような引数の関数を見つけました。
多分これを参考にしたのではないかと思います。

char* GetCSV(char** pBuf)
{
char*p = *pBuf,*q = p;
if (!p) return p;
if (*p == '"') {
*p++ = 0;
do ++q; while (*q && *q != '"');
if (*q == '"') *q++ = 0;
}
if ((*pBuf = strpbrk(q,",")) != 0) *(*pBuf)++ = 0;
return p;
}

当方がやりたい処理はVB6でCSVをリードして処理しているのですが、処理速度が遅いため
I/OをしているところをCに変更して処理速度が向上するか確認したいのです。
他にも色々調べたのですがstrtokを使って処理されている方が多いようなのですが、
"1,,2,3"と言うデータの場合に"1" "2" "3"と返ってくるようで、
私のほしい値としては"1" "" "2" "3"というように返ってきてほしいのです。

上記のGetCSVでは"1" "" "2" "3"に返ってくるようです。

何とか動くようにと下の関数をかぶして実行して見たところ結果は正しかったのですが
どうもメモリリークをしているように思います(タスクマネージャーのメモリ使用量は増えていく)

int split(char *ary[], char *s)
{
  intlen = 0;
  intlsize = 0;
char*strBuff[BUF_SIZE];

*strBuff = strdup(s);
lsize = strlen(*strBuff);

for (len = 0; len < lsize; len++) {
if ((ary[len] = GetCSV(strBuff)) == NULL)
break;
}
free(*strBuff);
return len;
}

strdupの後メモリを開放しているつもりなのですが問題あるのでしょうか?

C言語をあまりしたことがないので詳し方ご教示願えないでしょうか?宜しくお願いします。

C言語 ポインタ型引数の呼び出しについて2

以前質問した関数ですが、ネットを検索していたら同じような引数の関数を見つけました。
多分これを参考にしたのではないかと思います。

char* GetCSV(char** pBuf)
{
char*p = *pBuf,*q = p;
if (!p) return p;
if (*p == '"') {
*p++ = 0;
do ++q; while (*q && *q != '"');
if (*q == '"') *q++ = 0;
}
if ((*pBuf = strpbrk(q,",")) != 0) *(*pBuf)++ = 0;
return p;
}

当方がやりたい処理はVB6でCSVをリードして処理しているのですが、処理速度が遅いため
I...続きを読む

Aベストアンサー

> strdupの後メモリを開放しているつもりなのですが問題あるのでしょうか?
関係ないところをstrdupで確保したメモリ領域だと思ってfreeさせてますね。
GetCSV関数の中でif ((*pBuf = strpbrk(q,",")) != 0) *(*pBuf)++ = 0;という箇所がありますが、これによってsplit関数の*strBuffの値が書き換えられています。つまり、これが行われたあとにfree(*strBuff);してもメモリアロケータが知らないポインタをfreeしてほしいと申請しているわけなので、strdupで作られた領域はfreeされません。
正常にfreeしたいならstrdupしてからGetCSV関数を呼ぶまでの間に*strBuffのコピーをとっておく必要があります。

しかし、freeできるようになってもさらに問題があります。
ary[...]の指している値はstrdupしたメモリ領域を指しているので、strdupした領域をfreeしてしまうとaryの指している領域が無意味になってしまいます。多くの場合はメモリがすぐに再利用されないので問題に気づかないかもしれませんが、これはのちのちに見つけにくいバグになります。

そもそも、メモリの確保や開放をどこかの関数で勝手にやるとバグの温床になります。確保したところで開放するというのはよいとは思いますが、確保したメモリ領域を呼び出し元が使う場合はこの実装を避けた方がよいでしょう。つまり、splitの呼び元でstrdupしてからsplitの引数として渡す方がよいでしょう。
そうすると、例えばこんなプログラムになるでしょうか。

/*
* CAUTION: May change the argument 's'.
*/
int
split(char *ary[], const int ary_nelms, char *s)
{
int len = 0;

for (len = 0; len < ary_nelms; len++) {
if ((ary[len] = GetCSV(&s)) == NULL)
break;
}
return len;
}

int
main(void)
{
char str[] = "a,b,c,,e", *tmp, *ary[BUF_SIZE];
int i, len;
tmp = strdup(str);
len = split(ary, BUF_SIZE, tmp);
for (i = 0; i < len; i++)
printf("%s\n", ary[i]);
free(tmp);

return 0;
}

あるいは、もし、splitの引数が質問で示された形に決まっているとしたら、こんな感じで作るでしょうか。この場合、aryのサイズが小さすぎるとメモリを破壊しますし、split二度呼び出すと前回のsplitの結果が失われ、無意味なものになってしまいます。
static char *csv_string = NULL;
int
split(char *ary[], char *s)
{
int len, lsize;
char *csv_buff;

if (csv_string != NULL)
free(csv_string);

csv_string = csv_buff = strdup(s);
lsize = strlen(s);
for (len = 0; len < lsize; len++) {
if ((ary[len] = GetCSV(&csv_buff)) == NULL)
break;
}
return len;
}

自分だったら可能な限り前者の実装にしますね。

> strdupの後メモリを開放しているつもりなのですが問題あるのでしょうか?
関係ないところをstrdupで確保したメモリ領域だと思ってfreeさせてますね。
GetCSV関数の中でif ((*pBuf = strpbrk(q,",")) != 0) *(*pBuf)++ = 0;という箇所がありますが、これによってsplit関数の*strBuffの値が書き換えられています。つまり、これが行われたあとにfree(*strBuff);してもメモリアロケータが知らないポインタをfreeしてほしいと申請しているわけなので、strdupで作られた領域はfreeされません。
正常にfreeしたいならst...続きを読む

Qワークシート関数とはどのことなのですか?

【1】エクセルのワークシート上で使う=TODAY()などの関数

【2】VBAのCountなどのWorksheetFunction

【3】VBAのLENなどの関数

どれのことを俗に言う「ワークシート関数」と言うのでしょうか?
VBAで使う【2】【3】のことですか?

Aベストアンサー

ワークシート上で使う関数のこと。つまり1です。

QC言語のポインタとスタックポインタ

プログラム始めて1ヶ月の初心者です。
C言語のポインタとスタックポインタというのは同じなのでしょうか。
スタックポインタの考えは大体理解出来たのですが
C言語のポインタとなるとコードを見てもサッパリ分かりません。
ネットで調べても出てこなかったのでどなたか教えて下さい。
よろしくお願いします。

Aベストアンサー

★紹介
・スタック・ポインタを理解するにはスタックの動きをお勉強して下さい。
 下にアセンブラ入門のサイトを紹介します。
 C言語のポインタを学習するのに一番の近道はメモリ・イメージを
 紙などに描きアドレスを考えることです。
 また、アセンブラをちょっとお勉強すればポインタの理解も早いかもしれない。
・ちなみにポインタを簡単に説明するとデータ型とアドレスの2つの情報を持つもの。
 例えばアセンブラでアドレスが0x1000のとき
 アドレスに+1すると0x1001になります。
 ポインタに+1するとデータ型によって加算される値が変わります。
 つまり
 char *pc→char型は1バイトなので0x1001となる
 long *pl→long型は4バイトなので0x1004となる
 double *pd→double型は8バイトなので0x1008となる
 このようにポインタはデータ型により+1した時にアドレスに加算される値が異なります。
 ※通常はポインタのアドレス値を考えなくて良い。アセンブラではないので。

参考サイト:
http://www5c.biglobe.ne.jp/~ecb/assembler/assembler00.html
http://www5c.biglobe.ne.jp/~ecb/assembler/4_7.html
http://www5c.biglobe.ne.jp/~ecb/assembler/4_8.html

★紹介
・スタック・ポインタを理解するにはスタックの動きをお勉強して下さい。
 下にアセンブラ入門のサイトを紹介します。
 C言語のポインタを学習するのに一番の近道はメモリ・イメージを
 紙などに描きアドレスを考えることです。
 また、アセンブラをちょっとお勉強すればポインタの理解も早いかもしれない。
・ちなみにポインタを簡単に説明するとデータ型とアドレスの2つの情報を持つもの。
 例えばアセンブラでアドレスが0x1000のとき
 アドレスに+1すると0x1001になります。
 ポインタ...続きを読む


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

人気Q&Aランキング

おすすめ情報