引越しでおトクなインターネット回線は?>>

引数に対する制限値チェック方法

 プログラミング(組み込み系C言語)関数作成時にいつも私が迷ところなのですが、
 関数の引数に対する制限値(範囲外)チェックどうするか、次の(1)、(2)で悩んでます。。
  【1】関数内で制限値チェックで行い、制限値外であれば戻り値でエラーコードを返す。
  【2】関数呼び出し時に、引数となる値(変数)をチェックし、制限値内であることを確認してから、関数を呼び出す。

 上記の【1】、【2】の方法どちらがよいでしょうか?
 状況にもよるとは思うのですが、その場合はどういった状況時に(1)||(2)がよいのか教えてください。
 (【3】もあればお願いします。)

 --【1】がお勧めの場合の質問
 (1)本関数での"結果"を返したいときどうすればよいかアドバイスください。
    戻り値("結果")と、エラーコードを兼用するのはなんかイヤです。。
    エラーコード付き関数は、全て同じ戻り値(1:OK時、-1:NG時 みたいに)
    としてまとめたいからです。
 (2)極端にほとんどの関数の戻り値を、OK/NG とす。これってどうですか?、


///////////////////////
 【1】、【2】の利点、欠点を僕なりに考えてみました。

 ##【1】の利点/欠点
 利点:
  ・本関数呼び出し時に、毎回制限チェックをしなくてよくなる。
   (汎用的に様々な場面で、使用するのであればこれは良い利点だと思います。)
 欠点:
  ・戻り値のとして、エラーコードを返さなくてはならないため、本関数での結果を返したい場合、
   以下方法をとらないといけない。
     1、引数をポインタとして、その引数で値を返す。
     2、戻り値として、エラーコードと兼用して返す。
       (例:エラー時の戻り値 = 0、正常にの戻り値 = 1~ 255)

 ##【2】の利点/欠点
 利点:
  ・エラーコードを返す必要がなくなるため、戻り値が有効利用できる。
 欠点:
  ・関す呼び出し毎に、制限チェックが発生し、制限チェック忘れが発生する。
   (汎用的に使うにのであればなお・・・)

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

A 回答 (5件)

私も何度も考えたことがある疑問ですね.



C++ とか C# でも,こういう場合 "例外処理" という方法を使ってしっかり対処するくらいなので,
間違いなく【1】が有利だと思います.

例外処理を使えないとなると,"結果をもらうのにポインタ引数を使う" ということがしばしば出て
きてしまいますよね.

分かっていても,やはり見苦しいものがあります.

エラーか否かを 0 か 1 (C++ とかで言う bool) で返しつつポインタにした引数に値を入れようと
すると,0 (エラー) を返すときに引数に何を入れて返してよいか分からなくなるからです.

確かに,"どうせエラーだから何でもイイ" のですが,"何でもイイ" というコードを書くこと自体
ナンセンスで,スマートではないですよね.

それに,基本的には "結果" を "メソッドに対する戻り値"として期待しているのに,わざわざ
引数として与えなければならないところに違和感を感じます.
(当然,メソッドに "結果" をふたつ同時に求めない場合ですが)

それ以外にも,プログラムのリーダビリティを損なうというか,読んでいて気分が悪くなりますよね.

例えば,以下の Type A と Type B のどっちが読みやすいかということについてですが,きっと
Type A の方を好む方が多数だと思います.


//------------------------------------------------------------------------------

※ input には何が入っているか分からない
※ Type B の FunctionFoo は,エラーのときは 0,そうでないときは 1 を返す


//**************************************
// Type A
//**************************************

if( この条件式を満たさないための値 != input )
{
  int output = FunctionFoo(input);
  /* output を使用するその後の処理 */
}


//**************************************
// Type B
//**************************************

int output;

if( FunctionFoo(&output, input) )
{
  /* output を使用するその後の処理 */
}

//------------------------------------------------------------------------------


結論から言うと【1】になるのですが,やはり理想としては Type A のようなリーダビリティも
求めたくなるのが現状です.
(つまり,例外処理を使えないことに苦言を呈したい)
    • good
    • 0
この回答へのお礼

やっぱり引数で結果をうけとるってなんかスッキリしないですよね~
Type Aでも関数呼び出すたんびに制限チェックしていたら、
なんかリーダビリティも低くんっているような気がします。

これだって方法ないんでしょうか??

お礼日時:2008/02/08 00:20

ANo.4補足


> >【3】関数内で制限値チェックで行い、制限値外であれば呼び出し元には戻らない。
> これは制限値外ならばプログラムを停止するということなのでしょうか?

そう。プログラムに間違いがあるとどんな被害が発生するか分からないので可及的速やかに停止させるべきという考えです。
# プログラムに間違いがなければ制限値外にはならないことが前提です

> また、結論としては、【1】、【2】どちらも必要と考えてよいんでしょうか?


基本的に【2】です。ただそれだけだと間違いの発見ができないのでデバッグ用にassertを入れましょうということです。
assertだとリリース時にはチェックしません(参考URL参照)。当然、プログラムはassertがチェックしなくても問題のないコードでなければいけません。関数内で制限値チェックをしているから呼び出し側ではチェックしないというようなコードは許されません。
# もちろんロジック的に制限値を外れる恐れはないからチェックしないというのはOKです

参考URL:http://www.linux.or.jp/JM/html/LDP_man-pages/man …
    • good
    • 0

一般的に安全性を考えて【1】を行う場合が多いようですが、プログラムを複雑化させてバグを増やす原因になります。


下記URLの「オブジェクト指向入門」に書かれている「契約による設計」の概念に沿えば、【2】の方がお勧めでしょうね。
# http://www.seshop.com/detail.asp?pid=7595

ただ上記書籍でも関数の入り口でのチェックは行っているので、正確には次の方法が良いと思います。
【3】関数内で制限値チェックで行い、制限値外であれば呼び出し元には戻らない。

具体的にはassertを使って制限値チェックを行うか、同様の自作関数(マクロ)を用意してデバッグに活用する。
# 自作関数ならデバッグ時にはこの関数内にブレークポイントを置けば確実に捕捉できスタックトレースなども取れる

この方法は、【1】のインタフェースが複雑化する欠点と【2】の制限チェックを忘れる欠点の両方をカバーすることができます。
なお、呼び出し側の制限チェックを省くことはできません。制限を満たさない呼び出しはあってはいけないからです。

この回答への補足

>【3】関数内で制限値チェックで行い、制限値外であれば呼び出し元には戻らない。
これは制限値外ならばプログラムを停止するということなのでしょうか?
また、結論としては、【1】、【2】どちらも必要と考えてよいんでしょうか?

補足日時:2008/02/08 00:03
    • good
    • 0

あらゆる場面において【1】にするべきです。


制限値チェック云々より、「責任範囲の明確化」です。

【1】のルールでその関数の責任が明確化されます。

使う人によって、毒になる関数があったら、
障害が起きたときに追跡が大変です。

障害の原因を探すときには、コードのどこからどこまでが、
シロか調査範囲を切り分けますが、【2】のポリシーで作成した
関数の使用箇所が、ありとあらゆる場所にちりばめられていたら、
シロと言える場所がなくなり、ソースコードを全探索する羽目になります。

「A君の作った関数、変な値入れられたらどうなるの?」
って突っ込まれたら、どうします?
「僕の作った関数は入力チェックをしていますから、エラーを返します」
と、言えたら良いですが、
「使う人がちゃんとチェックしていれば、問題ないですが、範囲外の値を入れられた
場合の動作はわかりません。」
なんて言ったら、
「それじゃ、使用箇所全体が信用できんじゃないか。」
となってしまいます。

さらに、チェック忘れ以外に、チェックミスも発生することも忘れないで下さい。
断然チェックミスのほうがたちが悪いです。

まあ、【2】でやってみて、痛い目を見るのも良い経験でしょうが、
周囲の信頼を得たいなら【1】のポリシーでいくのが固いと思いますよ。

>戻り値("結果")と、エラーコードを兼用するのはなんかイヤです。。
>極端にほとんどの関数の戻り値を、OK/NG とす。これってどうですか?、

頭の中まで、論理回路にしなくても良いですよ。
戻り値=成否、エラーコードを返すと固定的に考えるからイヤになるのでは?
エラーコードじゃなくて、結果だと思えば、
0:異常なし
1:故障1
2:故障2
3:故障3
と思えば、自然じゃない??
if( result == 0 ) {
 // 異常なし
} else {
 // 故障
}
    • good
    • 0
この回答へのお礼

【1】で責任の明確ですか。。そのとおりですね!
【1】がよい気がしてきました!
痛い目あうのはいやです・・

お礼日時:2008/02/08 00:17

下記のようにしてはだめですか?


質問者さんの「1」の簡素化で別々の関数にします。
あまり気に入らないかもしれませんが…

<サンプル>

#define FUNC(n) (n>=0)?func(n):err()
// 上行の「n>=0」の部分に範囲内の条件

int func(int N)
{
printf("正常範囲です\n");
// エラー発生時は、return エラー値>0
return 0;
}

int err(void)
{
printf("範囲外です\n");
return -1;
}

int main()
{
FUNC(1); // 範囲内
FUNC(-2); // 範囲外
return 0;
}
    • good
    • 0
この回答へのお礼

なるほど、こんな工夫もできるのですね!
参考になりました。ありがとうございます。

お礼日時:2008/02/08 00:14

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

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

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

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

QLNK2019: 未解決の外部シンボルのエラーが出る

Microsoft Visual Studio 2008
Version 9.0.21022.8 RTM
Microsoft .NET Framework
Version 3.5 SP1
----------------------------------------------------------------
新しいプリジェクト→Win32 コンソール アプリケーション(ソリューションのディレクトリを作成 チェック外す)→Windows アプリケーション(空のプロジェクト チェック外す)
----------------------------------------------------------------
 プログラム

 mymain.cpp
#include "myhelper.h"
#include "mymain.h"

//自キャラのデータ
Point2D g_jikipos = {40, 400};//自キャラの座標

//画像ハンドル
int g_jikiimage[11];

//色々なファイルの読み込み
int LoadFiles(){
//画像ファイル読み込み
if(LoadDivGraph("media\\player01.bmp",
11,11,1,64,64,g_jikiimage) == -1) return -1;

return 1;
}


 mymain.h
//他から呼び出させるMyMainの関数
void MyMain();
int LoadFiles();


 myhelper.h(サンプルなので打ちミスはない)
#include "DxLib.h"
#include <limits.h>
#include <math.h>

//構造体宣言
//座標またはベクトルを記録する構造体
struct Vector{
float x,y;
};
typedef Vector Point2D;
//線を記録する構造体
struct Line2D{
Point2D startpos, endpos;
float katamuki;//傾きをラジアン値で記録
Vector speed;//移動している場合は速度をセット
};
//球体を記録する構造体
struct Ball2D{
Point2D position;
float hankei;//半径
};
//四角形を記録する構造体
struct Rect2D{
Point2D lefttop;
Point2D rightbottom;
float width;
float height;
};


//ライブラリ関数
Point2D PosInView(Point2D in);
int XInView(float inx);
int YInView(float iny);
void ScrollToLeft(float jikiposx);
void ScrollToRight(float jikiposx);
void ScrollToUp(float jikiposy);
void ScrollToDown(float jikiposy);
void DrawLineInView(float x1, float y1, float x2, float y2, int Color, int Thickness);
void DrawCircleInView(float x, float y, float r, int Color, int FillFlag);
void DrawAnimation(float x, float y, double ExtRate, double Angle,int TurnFlag,
int *imgarray, int allframe, float fps);
//ベクトル関数
Vector CreateVector(Vector in, float veclen);
Vector AddVector(Vector v1, Vector v2);
Vector SubVector(Vector v1, Vector v2);
Vector AddVectorInFrameTime(Vector pos, Vector speed);
Vector AddVectorInFrameTime2(Vector pos, Vector speed, Vector accel);
Vector Normalize(Vector in);
Vector RotateVector(Vector in, float radian);
float VectorLengthSquare(Vector in);
float DotProduct(Vector v1, Vector v2);
float CrossProduct(Vector v1, Vector v2);
void SetLine2DKatamuki(Line2D *in);
void DrawLine2D(Line2D in, int Color, int Thickness);
void DrawBall2D(Ball2D in, int Color, int Fill);
//当たり判定関数
bool HitTestLineAndBall(Line2D linein, Ball2D ballin);
bool IsPointAtLineFace(Line2D linein, Point2D ptin);
bool HitTestLineAndLine(Line2D line1, Line2D line2);
bool HitTestBallAndBall(Ball2D a, Ball2D b);
bool HitTestPointAndBox(Rect2D rect, Point2D pt);
//タイマー関数
void SetSimpleTimer(int idx, int time);
int GetPassedTime(int idx);


//グローバル変数
extern float g_frametime;
extern Rect2D g_framerect;//画面領域(当たり判定)
extern Point2D g_current_field_pos;//現在の左上座標
extern Rect2D g_stagesize;//ステージサイズ

//定数宣言
const float ZEROVALUE = 1e-10f;
const float PIE = 3.1415926f;
const int SCROLL_LIMIT = 200;
----------------------------------------------------------------
 エラー内容
1>myhelper.obj : error LNK2019: 未解決の外部シンボル "void __cdecl MyMain(void)" (?MyMain@@YAXXZ) が関数 _WinMain@16 で参照されました
1>C:\Documents and Settings\Owner\My Documents\Visual Studio 2008\Projects\my\Debug\my.exe : fatal error LNK1120: 外部参照 1 が未解決です
1>my - エラー 2、警告 0
ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ
----------------------------------------------------------------
画像を貼り付けときます
(見えにくい場合→http://www.dotup.org/uploda/www.dotup.org154142.jpg.html)
初心者なのでわかりやすくお願いします

Microsoft Visual Studio 2008
Version 9.0.21022.8 RTM
Microsoft .NET Framework
Version 3.5 SP1
----------------------------------------------------------------
新しいプリジェクト→Win32 コンソール アプリケーション(ソリューションのディレクトリを作成 チェック外す)→Windows アプリケーション(空のプロジェクト チェック外す)
----------------------------------------------------------------
 プログラム

 mymain.cpp
#include "myhelper.h"
#include "mymain.h"

//自...続きを読む

Aベストアンサー

ファイル構成から推測するに
mymain.cpp というファイルに
void MyMain(void) {
// ここに処理を書く
}
という関数が必要なようです。

Q複数桁10進数の*桁目だけを抽出したい

タイトルがすべてと言えてしまうのですが、
例えば、int宣言された"4287"(この値は変動します)という数値があったとして、1桁目の"7"だけを別の変数へ引き抜きたいのですが、その場合にはANDによるマスク処理による演算で処理可能なのでしょうか?
また、他に良い方法などありましたら教えていただけますでしょうか?

Aベストアンサー

★10進数ですので AND は使えませんね。
・簡単なサンプルを載せますので読み取って下さい。

サンプル1:
int value = 4287;
int a[ 4 ];

a[0] = (value % 10); value /= 10; // 1桁目を取り出す
a[1] = (value % 10); value /= 10; // 2桁目を取り出す
a[2] = (value % 10); value /= 10; // 3桁目を取り出す
a[3] = (value % 10); value /= 10; // 4桁目を取り出す

サンプル2:
int value = 4287;
int a;

a = (value % 10);
value -= a;

value → 4280
a → 7
になります。

Qファイルやディレクトリの存在確認を行う方法

ファイルをオープンするのはfopenでOKですが、ファイルやディレクトリの存在確認を行う方法が知りたいです。

何か組み合わせて作るものなのでしょうか?
perlとか便利な演算子があるのですが、C/C++って器用ではないですね。
これは処理系?依存の内容ですか?

私の環境は VC6, VC2005 Windows2000です。

Aベストアンサー

int access(const char* path, int mode);
int stat(const char* path, struct stat* sb);

かな?
MSDN を引くと _access_s() を使えとか書いてあるけど。

Qmain関数のコマンドライン引数の上限?

実験のデータ整理のために50個くらいのテキストデータを処理するプログラムを作ったつもりなのですが

main(int argc, char *argv[])
の*arg[]のところに30個以上の引数を持っていけません。

ドラッグ&ドロップで、プログラムにデータを持っていこうとすると
「指定されたデバイス、バス、またはファイルにアクセスできません。アクセス許可がない可能性がありません。」
という警告メッセージがでます。
何か方法はないでしょうか?

Aベストアンサー

★過去にも同様な質問がありましたよ。
>の*arg[]のところに30個以上の引数を持っていけません。
 ↑
 私の環境では25個前後です。
>ドラッグ&ドロップで、プログラムにデータを持っていこうとすると
>「指定されたデバイス、バス、またはファイルにアクセスできません。アクセス許可がない可能性がありません。」
>という警告メッセージがでます。
 ↑
 OSの制限によるものだと思います。
>何か方法はないでしょうか?
 ↑
 エクスプローラからファイルを選択したら右メニューより『コピー(C)』を選択します。
 その後にプログラムからクリップボードの HDROP ハンドルを取得すれば選択された
 すべてのファイルパスを取得できます。この方法ならドラッグ&ドロップしないで
 プログラムを起動すれば良いので argc、argv は不要になります。
・まずは過去質問を読んでみて下さい。
 http://oshiete1.goo.ne.jp/qa3222390.html→『コンソールアプリの起動パラメータ について』
 このリンクの回答 No.4 に文字数の確認用のサンプルを載せています。
 ドラッグ&ドロップしたときはフルパス名で 2100 バイトまで受け取れるようです。
 よって1つのファイルのパスが深いとあまり多くのファイルを渡せません。
 逆にルートのパス(C:\)なら100個以上のファイルをドラッグ&ドロップで渡せます。
・以上。ファイルの受け渡しインタフェースを考え直してみましょう。

参考URL:http://oshiete1.goo.ne.jp/qa3222390.html

★過去にも同様な質問がありましたよ。
>の*arg[]のところに30個以上の引数を持っていけません。
 ↑
 私の環境では25個前後です。
>ドラッグ&ドロップで、プログラムにデータを持っていこうとすると
>「指定されたデバイス、バス、またはファイルにアクセスできません。アクセス許可がない可能性がありません。」
>という警告メッセージがでます。
 ↑
 OSの制限によるものだと思います。
>何か方法はないでしょうか?
 ↑
 エクスプローラからファイルを選択したら右メニューより『コピー(...続きを読む

Q戻り値の意味がわかりません…

戻り値とはどういう値なのか簡単な例文で教えて頂けますか?

Aベストアンサー

バカくさいかもしれませんが簡単な例えをだしてみます。
2人の子供がいて、名前をそれぞれ太郎・花子にしましょう。この2人の子にある役割を決めます。
・花子は飴をもらうと、それをチョコにする役割。(できるかは別として)
・太郎は花子を呼んで飴をあげる役割。

さてこの例では太郎の飴が引数(ひきすう)になり
花子のチョコが戻り値になります。

このイメージを元に次の文を読んでみてください。

「プログラム中の関数やサブルーチンが処理を終了し
呼び出し元に処理の結果として返す値。」

これが戻り値の正しい定義です。
そのほかにはNo1さんのような役割指すときも、それを「戻り値」と呼んだりします。

Q戻り値で構造体を返すことは可能でしょうか?

perlでは以下のように2つの戻り値が可能ですが、C言語では
それができるのでしょうか?
my (ret1, ret2) = test1();

よくやるのは、引数にポインタを渡して、内容を書き換える手を使っていますが、戻り値を複数返せたら、直感的にわかりやすいかなと思いまして・・・

Aベストアンサー

C言語から遠く離れた者ですが、

>>> よくやるのは、引数にポインタを渡して、内容を書き換える手を使っています

これが常識でしょう。これが直感的に理解できるようにC言語を身に付ける必要があるのではないでしょうか。

Qラッパーって何なんでしょう・・・?

C++を勉強し始めたのですが、何とも難しい言葉が多くて、書いてあることが本当に理解できません。
ラッパーって?
ハンドルって??
と、次から次へと理解不能な言葉が・・・
読んでいるのは、C++Builderの開発者ガイドと、プログラミング言語C++の本です。
具体的なイメージが浮かばず、概念自体もピンときません。
わかりやすい本などあったら教えてください。
また、とりあえずラッパーとハンドルがどうしても気になるので、この2つの意味教えてください!!
よろしくお願いします。

Aベストアンサー

ラッパーは、wrapper で包み込むものの意味です。
wrap ラップはサランラップのラップですね。
wrappingラッピングといえば、プレゼントを包むやつですね。

つまり、たとえばある関数を使いたいと思ったとします。
しかし、その関数を呼び出すには、いろんな手続きをしないといけない、また呼ぶときに渡す引数をたくさん設定しなければならないなど、使用するのが面倒な場合があります。
これはその関数が汎用的に使えるように、動作に自由度を持たせていると、面倒になる傾向にあります。

そんな時、引数なし、又は簡単な引数で呼び出せるような関数を作ってあげれば楽になります。
この場合は、ある程度用途が決まっているので、その関数を呼び出すときの手続きを省略してくれるような関数ですね。
それがラッパーというわけです。

あと良くあるのが、C言語で書かれたライブラリなどをC++の機能を使って使いたいときに、ラッパーを作ったりします。
この場合は逆に機能を追加して使いやすくするイメージですね。

ハンドル(handle)はつまり何かを操作するときのハンドル(車のハンドルと同じ)です。

この概念は良く使われます。
たとえば、ハードディスクにはファイルがたくさん入っています。
その中のファイルを開いて何か処理しようとします。するとディスクアクセスの処理をしなければなりませんが、それを自分で書くのは大変なので、ライブラリを使います。
ライブラリでは、
・指定されたファイルを開く関数
・指定されたファイルの中身を読み出す関数
・指定されたファイルに指定の文字を書き出す関数
などなどたくさん用意します。

ここで一つ問題が生じます。もし複数のファイルを同時に処理したい場合どうやったらよいでしょう。
いちいちファイル名で指定する方法も考えられますが、ファイルを開くときに一つのハンドルという名前の変数を用意し、その変数の中にどのファイルであるという情報、そのファイルのサイズ、そのほか必要な情報を一つにまとめておくと、ファイルを操作するときにはその変数を引数として渡すだけで、ファイルがどれであるのかという指示が簡単に出来ます。

いまファイルハンドルを例にあげましたが、他にもWindowsではたくさんのWindowを開きますので、それら一つ一つにもハンドルが用意されています。

基本的に、

・同種のものが複数ある
・上記に対して操作する関数が複数ある

という条件を満たすようなものに対しては、ハンドルという概念でコントロールすることがよくあります。

ラッパーは、wrapper で包み込むものの意味です。
wrap ラップはサランラップのラップですね。
wrappingラッピングといえば、プレゼントを包むやつですね。

つまり、たとえばある関数を使いたいと思ったとします。
しかし、その関数を呼び出すには、いろんな手続きをしないといけない、また呼ぶときに渡す引数をたくさん設定しなければならないなど、使用するのが面倒な場合があります。
これはその関数が汎用的に使えるように、動作に自由度を持たせていると、面倒になる傾向にあります。

そんな時、引...続きを読む

QDWORDの実際の型は何でしょうか

VC++.NETの環境です。
DOWRD dw1 = 1;
int i = 2; と定義し
ここで
if ( i > dw1 ){
何かの処理;
}
とコーディングすると
warning C4018: '>' : signed と unsigned の数値を比較しようとしました。
のワーニングがでます。
これは、DWORDがint型でなくunsigned int型のようにも見えます。
ある本によれば(VC++.V.NET逆引き大全500の極意)
DWORD はint型であると記述されています。
もし、int型ならこのワーニングはでないはずなのですが、
なぜでるのでしょうか。又、DWORDの実際の型は何なのでしょうか。ご存じのかたおりましたら、教えていただけませんでしょうか。

Aベストアンサー

型定義が知りたいのならば、宣言ファイルを見れば疑問を挟む余地もありません。
DWORD型はwindef.hで
"typedef unsigned long DWORD;"
と宣言されています。

Visual Studioを使っているのならば、知りたい型の上にマウスポインタを置いて右クリック、ポップアップメニューの「定義へ移動」または「宣言へ移動」で簡単に知ることが出来ます。

QC言語にて構造体のメンバがNULLであるかを判定するサンプルを作成して

C言語にて構造体のメンバがNULLであるかを判定するサンプルを作成しています。
一応目的の動作はするのですが、プログラミングとして正しいか教えて頂ければと
思います。

<test.c>

int main()
{
/* ---------------------------------------- */
/* 構造体のメンバ(NULL保障無し)がNULLか */
/* 比較するサンプル */
/* ---------------------------------------- */

char buf[50];
/* サンプル構造体 */
struct ST_test {
int cd;
char name[10];
int no;
};

struct ST_test st_test; /* 構造体定義 */
memset(&st_test,0x00,sizeof(st_test)); /* 構造体初期化 */
memset(&buf[0],0x00,sizeof(buf)); /* 構造体初期化 */

/* 構造体に値セット */
st_test.cd = 12;
memcpy(&st_test.name[0],"aabbccddee",sizeof(st_test.name));
st_test.no = 999;

/* NULL判定 */
if(*st_test.name == 0x00)
{
printf("NULLです\n");
}
else
{
printf("NULLではないです\n");
}

return (0);

}

C言語にて構造体のメンバがNULLであるかを判定するサンプルを作成しています。
一応目的の動作はするのですが、プログラミングとして正しいか教えて頂ければと
思います。

<test.c>

int main()
{
/* ---------------------------------------- */
/* 構造体のメンバ(NULL保障無し)がNULLか */
/* 比較するサンプル */
/* ---------------------------------------- */

char buf[50];
/* サンプル構造体 */
struct ST_test {
int cd;
...続きを読む

Aベストアンサー

1)先頭が'\0'でない文字列をmemcpy()したのだから、*st_test.nameは'\0'でないのに
  決まっている。そもそも'\0'との一致判定をすることに意味があるのかどうか。
2)標準関数のプロトタイプ宣言を行なっているヘッダーファイルをインクルードしていない。
3)&buf[0]はbufと省略できる点を理解しているかどうか。
4)memcpy()で、文字列終端を含めて11バイトのデータを10バイトの領域にコピーしている。
  プログラムの仕様として正しいかどうか。
5)#1さんの回答のとおり、NULLと'\0'との違いをじゅうぶん理解できているかどうか。

Q「コマンドライン引数チェック」て何

#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
char gyou[1024];
int gyousuu = 0;
if ( argc < 2 ){
printf("file mei ga nai\n");
return -1;
}
fp = fopen(argv[1], "r");
if ( fp == NULL ){
printf("fopen dekinai\n");
return -2;
}
while(fgets(gyou, sizeof(gyou), fp) != NULL){
gyousuu++;
}
fclose(fp);
printf("gyousuu=%d\n", gyousuu);
return 0;
}
 
 以上のプログラムはご覧のとおり、「ファイルの行数を計算」のプログラムです。

さて以上の
 if ( argc < 2 ){
printf("file mei ga nai\n");
return -1;
}
は「コマンドライン引数チェック」を行っています。・・・
 if ( argc < 2 ){の「argcは2以上である必要がある」と参考書に書いてあります。
 
以上ですが意味が日光手前ですが、プログラムの行数をカウントするうえで、
 「コマンドライン引数チェック」とはどんな作業を行っているとこなのでしょうか!?
 よろしくお願いします。
 

#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
char gyou[1024];
int gyousuu = 0;
if ( argc < 2 ){
printf("file mei ga nai\n");
return -1;
}
fp = fopen(argv[1], "r");
if ( fp == NULL ){
printf("fopen dekinai\n");
return -2;
}
while(fgets(gyou, sizeof(gyou), fp) != NULL){
gyousuu++;
}
fclose(fp);
printf("gyousuu=%d\n", gyousuu);
return 0;
}
 
 以上のプログラムはご覧のとおり、「ファイルの行数を計算」のプログラムです。

さて以上の
 if ( argc < 2 ){
printf...続きを読む

Aベストアンサー

例えばプログラム名をhogeとした場合

hoge と起動した場合
argc = 1
argv[0] = "hoge"

hoge aaa bbb の様に起動した場合
argc = 3
argv[0] = "hoge"
argv[1] = "aaa"
argv[2] = "bbb"
↑の値が各変数にセットされます。
以後の処理で、それらの値を使用するのが
必須の場合、引数をつけずにプログラムを
起動したか、値が適切な物であるかどうか
を「コマンドライン引数チェック」で確認
してチェック結果に応じた処理をします。


人気Q&Aランキング

おすすめ情報