
C言語によるUNIXシステムにプログラミング入門という本を読みながらC言語を勉強しています。
しかし、サンプルとして提示された下記の内容の意味がわかりません。
分からない箇所が「関数ポインタ」と呼ばれるものがついているということが分かった程度で、どういう意図で記述されているのかがわかりません。
分からないプログラムの処理内容は、ファイル内のデータを16進数で表示するというものです。
分からない箇所を記します。
#include <stdio.h>
#define BUFF 17 /*buffer*/
#define ERR -1 /*system call error*/
void usage(void); /*put usage message*/
char *command_name /*command name*/
FILE *fpin; /*file pointer*/
main(int argc,char *argv[ ]){
char *rindex(const char*s,int c); /*末尾から文字列検索*/
void hexdump(void);
...
...
}
void hexdump(void){
...
...
}
void usage(){
...
...
}
不明なのは、main関数の中の
char *rindex(const char*s,int c); /*末尾から文字列検索*/
void hexdump(void);
です。
Cについて、不明なところが多いので、利用する関数は使う前に宣言しなければいけない程度の理解ですが、そうだとしてもusageメソッドはmain関数の外であるのに、rindexとhexdumpは何故main関数の中で宣言されているのでしょうか。
上記の不明点とは別で、rindexの前にポインタが付いていると思うのですが、hexdumpやusageにはついていません。
知人からは、関数までのポインタを返すとのことでしたが、用途もいまいち理解できません。
全てではなくてもいいので、ヒントをいただけるとうれしいです。
よろしくお願いします。
No.3ベストアンサー
- 回答日時:
これは関数ポインタではなくて、関数のプロトタイプ宣言ですね。
プロトタイプ宣言では、関数がどのような引数をとり、どのような返り値を返すかというのを記述します。char *rindex(const char*s,int c); /*末尾から文字列検索*/
void hexdump(void);
はconst char*型の引数とint型の引数を取って、char*型を返すrindexという関数と何も引数をとらず何も返さないhexdumpという関数を定義しています。こうすることでmain関数の中でこれらの関数が使われた場合に正しく型を認識することができるようになっています。
今回、main関数の中でおそらくrindex関数とhexdump関数が使われているのでこのように宣言しているのではないでしょうか。
プロトタイプ宣言の有効範囲 (スコープ) をmain関数の中に限定するのは無意味なので、プロトタイプ宣言は#includeの直後などに書かれるのが普通だと思いますけどね。
ちなみに、rindexはstrings.hに定義されているので#include <stdio.h>のあとに#include <strings.h>と書けばこんな変なことはしないでいいです。また、void hexdump(void);もusage関数の次の行に普通は書くものだと思います。
個人的にはこのプログラムをメンテナンスするくらいなら書き直します。プロトタイプ宣言をmain関数の中と外(usage関数)に分けるなど、なぞなプログラミングスタイルをしてくれています。また、hexdump関数が引数をとらずにFILE *fpin; /*file pointer*/をグローバルで宣言するというのも嫌ですね。グローバル変数を使っている関数はその関数の再利用性が著しく損なわれるので、理由がないとこの実装はしません。あと、stdlib.hをincludeしているわけですから#define ERR -1 /*system call error*/はいらないのではないかと予想します。
ご回答ありがとうございました。
プロトタイプ宣言は、mainの外で行うものと決めつけていた為、混乱していました。
グローバル変数ときくと、いろいろな箇所から自由に扱えるように思えるのですが、再利用性が失われるというのはどういったシーンでしょうか。
No.5
- 回答日時:
stdlib.hに定義されているエラーの EXIT_FAILURE を無視する「#define ERR -1」とか
http://www.geocities.jp/ky_webid/c/065.html
strings.hに定義されている文字列sの中に,文字列tが最後に現れる位置を返す char *rindex(const char*s,int c); を「末尾から文字列検索」するといった受け狙い(?)の関数プロトタイプ宣言とか
http://www.obihiro.ac.jp/~suzukim/masuda/octave/ …
プロトタイプ宣言は、以前のCがint型関数は型名を明記しない慣習からバグが入り易い欠陥があり、事前にCコンパイラに知らせて誤りを検出する機能を強化するために設定された経緯を無視した main()関数内での書法解説とか
http://ja.wikipedia.org/wiki/%E9%96%A2%E6%95%B0% …
たかが、ファイル内のデータを16進表示するのに、FILE *fpin; はおろか main(int argc,char *argv[ ]){ と引数まで取り込む複雑なプログラミング内容と想像できる初心者向け入門書である(?)とか
UNIX哲学を無視したC言語プログラミング入門書には、非常に興味があります。
http://en.wikipedia.org/wiki/Unix_philosophy
書籍名と著者を教えていただけませんか。
ちなみに、UNIXにおけるファイルの16進表示プログラムは↓のように簡単です。
使い方は UNIX哲学に習い、フィルターとしての機能を有し、次のようにコマンドラインを打ち込みます。
1.antis.c ソースファイルを 16進表示する。
./a.out<antic.c
2.意味はないけどパイプを使う。
cat<antis.c | ./a.out
/* Gcc on MacOSX
* Source file name: antis.c
*/
#include <stdio.h>
int main(void)
{
int c,count,offset,buf[3];
count=offset=0;
printf("00000 ");
while((c=getchar())!=EOF){
if(offset==0) {
buf[1]=c;
offset=1;
}else{
buf[0]=c;
printf("%02x%02x ",buf[0],buf[1]);
offset=0;
}
count++;
if(count%16==0) {
printf("\n");
printf("%05x ",count);
}
}
if(offset!=0)
printf("%02x%02x ",0,buf[1]);
printf("\n");
return 0;
}
ご回答ありがとうございました。
ご提示いただいたサンプルソースコードもわかりやすくて助かります。
今参考にしている書籍は河野清尊氏の「C言語によるUNIXシステムプログラミング入門」という書籍です。
No.4
- 回答日時:
No.1のものです。
あのままでは、分かりづらいと思ったので、補足。
関数のポインタは、次のように宣言します。
char (*function_name)(parameter_list);
最初のカッコにより、function_nameは、ポインタであり、次のカッコが付くことにより、それが関数であり、型名によって、その評価結果(この場合関数の戻り値)がcharである。
となります。
parameter_listは、普通の関数宣言時と同じ。
使い方はこんな感じ。
#include <stdio.h>
void hello(void){
printf("hello\n");
}
int main(){
void (*function_name)(void);
function_name=hello;
(*function_name)();
printf("こっちはメイン\n");
}
ご回答ありがとう御座います。
1度目の投稿に加え、ソースコードまでご提示いただきありがとうございました。
関数ポインタの挙動について理解する事ができました。
ありがとうございました。
No.2
- 回答日時:
全体がわからないので嘘言ってたらすいません
>usageメソッドはmain関数の外であるのに、rindexとhexdumpは何故main関数の中で宣言されているのでしょうか。
メソッドというか関数ですね
基本的にはどちらで宣言しても問題はありませんが
あえて分けられているのであれば
そういつソース内の他の関数があってそちらでも(複数個所で) usage を使ってる
rindexとhexdumpは main関数内でしか使わない ということなのかもしれません
>関数までのポインタを返す
違います この言い方が適切か分かりませんが
rindex 関数が charのデータ格納領域のアドレス(char *)を返す
ということを意味します
関数までのポインタを返すわけではありません
例えば 文字列 abcde がアドレス 100番地から順番にセットされていたとして
rindex を 使う事により
aの位置を検索する様な場合 アドレス 100 が返り
bの位置を検索する様な場合 アドレス 101 が返り
以後 同様 といったような関数の仕様になっているということです
(実際の処理内容に合わせていません あくまでイメージ)
voidに関しては有効な値がない事を意味します
ご回答頂きありがとう御座います。
rindexの挙動について理解する事ができました。
おっしゃる通り、main関数内でのみ利用している関数だったため、main内で宣言していたようです。
ありがとうございました。
No.1
- 回答日時:
関数の宣言は、
記憶クラス 型名 関数名(パラメータ宣言)
ですので、
char *が、charへのポインタ型と解釈されます。つまり、この関数はcharへのポインタを返す関数だということです。多分、末尾から検索して、見つけた文字へのポインタでも返す仕様なのでしょう。
また、関数のプロトタイプも、変数と同じように、宣言した場所によって、スコープルール(その名前の有効範囲)が制限されます。
つまり、rindexという関数は、main内でしか使えないはずです。
しかし、標準のCでは、関数は入れ子に定義できないので、あまり意味はないと思います。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語でユーザ関数を利用して入力された文字列を反転させるプログラムを作りたいです。 3 2023/01/29 19:47
- C言語・C++・C# const char** p;のとき、free(p)でC4090エラーとなるのはなぜですか 3 2023/03/31 16:28
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# スタックフレームの消滅 6 2023/05/20 12:33
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# Cのdoubleの浮動小数点表示について 3 2023/04/17 13:14
- C言語・C++・C# C言語初心者 構造体 課題について 1 2023/03/10 19:30
- C言語・C++・C# c言語の問題です 課題1 (二分探索木とセット) 大きさ size の配列 array を考える。す 2 2023/01/10 21:08
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
CStringからchar*への型変換に...
-
char*を初期化したいのですが
-
C言語のintとcharの違いってな...
-
char型にint型の数値を代入する。
-
C言語にて構造体のメンバがNULL...
-
fgetc( )の戻り値はなぜ整数??
-
char 文字列型 の表現範囲が-12...
-
fstream型オブジェクトを関数の...
-
C++17で、unsigned char * 配列...
-
DWORDとcharの変換
-
文字列内の数字削除
-
new charとnew char[N]の違いは?
-
文字型配列に格納した空白の切捨て
-
C++Builder 2009 テキスト...
-
csvファイルをfscanfで読み込む...
-
文字列の途中から途中までを抽出
-
[C] 構造体メンバーのカンマ区...
-
エクセルのMID関数は、C言語では?
-
小数点入りの文字列をfloat型に...
-
wsprintf( ポインタ , "%d" , "...
おすすめ情報