人に聞けない痔の悩み、これでスッキリ >>

char型の変数の扱いで悩んでいます。
具体的には以下の二つのプログラムの差異についてです。

----------------------
char c;

scanf("%c", &c);
printf("%c\n", c);

-----------------------
char c;

scanf("%s", &c);
printf("%s\n", &c);

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


上のプログラムは正しいと思うのですが、下のプログラムが正しいのかどうか、わかる方に教えていただきたいと思い質問させていただきました。

どちらのプログラムも問題なく動作します。
僕自身は 下のプログラムの printf 関数については間違った使い方なのではないかと思っています。

scanf("%s", &c) は入力された文字のうち、終端文字の手前までの文字を引数のポインタが示すオブジェクトへ順に格納していく関数だと理解しているので、入力された文字が一文字だった場合、&cの示すオブジェクトに文字が代入されると考えたからです。

逆に printf("%s", &c) は、&cの示すオブジェクトから”ヌル文字”の手前までの文字列を順に表示する関数だと理解しているので、問題なく動作しているのは&cで示されるオブジェクトの後ろの領域が偶然'\0'だったからではないかと考えたからです。

何かの本で、未使用の領域は0である確率が高いという記述をみたことがあり、'\0'は0と同じだということなので問題なく動作する率が高いのではないかと思っています。


僕の考え方がどの程度正しくて、正確にはどうなのかを教えて欲しいです。


ちなみに、

-----------------------
char c;
char str[100];

scanf("%s", str);
scanf("%c", &c);
------------------------

と書くと c には改行文字が代入されてしまいます。
scanf("%s", str);
において"aasssdd "と最後に空白を入れると
c には空白文字が代入されます。

しかし、
--------------------------
char str1[100];
char str2[100];

scanf("%s", str1);
scanf("%s", str2);
--------------------------
においては、
scanf("%s", str1);
で "asdfg "と最後に空白を入れても次のstr2が空白で始まることはありません。


この辺りの処理がどのような法則で実行されているのかが分かりづらくて悩んでいます。
おそらく、
scanf("%s", str);
の場合には最初の文字が空白や改行文字でも、その次に有効な文字があればそれらの改行や空白を無視するのではないかと思っています。


分かる方がいましたら回答をよろしくお願いします。

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

A 回答 (5件)

> char c;


> scanf("%s", &c);
char c では1文字分の領域しか確保されていないので、
1文字以上の文字列を無理矢理格納すると
他のデータが存在しているかもしれない領域を書き換えてしまいます。(メモリ破壊)

なお、'\0'はscanfが(本来書き込んではいけない領域に対してですが)書き込んでいます。


> と書くと c には改行文字が代入されてしまいます。
最初のscanfが改行文字を読み込んでいないからです。
以下のページに書かれている内容と本質的には同じ。
http://www9.plala.or.jp/sgwr-t/c/sec05.html#s5-

> 最初の文字が空白や改行文字でも、その次に有効な文字があればそれらの改行や空白を無視するのではないかと思っています。
そう考えて問題ないと思います。
    • good
    • 3
この回答へのお礼

回答ありがとうございます。
記載していただいたURLも非常に参考になりました。

お礼日時:2007/05/26 09:55

最初の方のコードは、scanf()使用の是非はともかくとして、


間違っているわけではありません。

char型は「int型やlong型よりも狭い範囲の整数」を扱う型で、
scanf()で標準入力から受け取った値を"%c"という書式文字列で受け取り、
-128~+127または0~255の範囲のいずれかの値をとる、
という状況はあっておかしくないです。
    • good
    • 3
この回答へのお礼

回答ありがとうございます。
正しいコードについて解説していただけて、参考になりました。

お礼日時:2007/05/26 10:18

いろいろと回答が出ていますが、一応。


----------------------
char c;
scanf("%c", &c);
printf("%c\n", c);
-----------------------
これはscanfの「指定した文字だけを読み込む」という
仕様から正しいプログラムです。
文字は文字列でないため、'\0'はありません。
但し、Enterなどで入力された改行文字が入力ストリームに残ります。

-----------------------
char c;
scanf("%s", &c);
printf("%s\n", &c);
-----------------------
これは文字列を読み込む時、領域の無い部分へ
書き込みを行うため誤ったプログラムです。
やってはいけません。

>何かの本で、未使用の領域は0である確率が高いという記述を
>みたことがあり、'\0'は0と同じだということなので
>問題なく動作する率が高いのではないかと思っています。
そもそも、確率なんていってる時点でダメダメですね。
スタティック変数などは定義された時初期化が保障されていますが、
ローカル変数などは初期化保障されていません。

-----------------------
char c;
char str[100];
scanf("%s", str);
scanf("%c", &c);
------------------------
>と書くと c には改行文字が代入されてしまいます。
上で書いたように、指定されず読み込まれなかったものは、
Enterなどで入力された改行文字が標準入力に残ります。

>"aasssdd "と最後に空白を入れると
>c には空白文字が代入されます。
>"asdfg "と最後に空白を入れても
>次のstr2が空白で始まることはありません。
これは上で少し述べましたが、矛盾した入力文字は読まれないまま
入力ストリーム上に残り入力中で後続し(改行文字を含む)
空白類は、指令に照合しない限り読み込まれないまま残る。
というscanfの指定子集合の仕様のためです。

scanfは多くの場合、バッファオーバーフローを起こすと言われますが、入力文字数の制限などは可能です。
    • good
    • 1
この回答へのお礼

詳細な回答ありがとうございます。
入力ストリームという概念とscanf関数の知識が足りなかったのだと分かりました。これからの学習に役立てていこうと思います。

お礼日時:2007/05/26 10:15

誤----------------------------


char c;

scanf("%s", &c);
printf("%s\n", &c);
誤----------------------------

例に上げられている後のプログラムは間違いです。たまたま正しく動いているように見えるだけです。
%sはNull終了の文字列を扱うので、通常は以下のように書きます。

正----------------------------
char str[100];

scanf("%s", str); // strは配列の先頭を示すアドレス
printf("%s\n", str);
正----------------------------

なお、scanfは、本当に「ちょっとお試しで入力」という「お勉強用」関数と考えたほうがいいですね。バッファオーバーフロー攻撃ってのもありますし。

質問者さんは、不可解な動作で悩まれていますが、その問題の原因が判ったとしても、使いにくいのは変わらないと思います。私は深く追求していません。scanf関数は通常は使いませんので。

その手の入力が必要な場合は、fgetsなどの1行単位で文字列入力を受け取ったあとに、sscanfで入力された文字列から、個々のデータを切り出すやり方を使っています。このほうがエラー検出も容易だし、使いやすいからです。

それから、蛇足ですが・・・.

C言語で、それなりに、まともに使える入力ルーチンを作ると、カーソル処理とか漢字対応や編集処理なども含めて、いろんな知識が必要で、コードも500行以上になる可能性があります。
最近はフォーム画面を使うので、画面処理もある意味で楽なんですが、エスケープコードを使ってCUI画面で入力処理するプログラムを作ると、結構勉強になります。ただし、あまり参考になる書籍が無い気がします。linuxのGNUライブラリにある1行入力ルーチン(たぶんあると思う)が見本になると思います。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
入出力についてはもっと勉強したいので、GNUライブラリも当たってみたいと思います。

お礼日時:2007/05/26 10:12

>僕自身は 下のプログラムの printf 関数については間違った使い方なのではないかと思っています。



どちらも間違っています。
1文字入力して、Enterキーで確定したとしても、最低でもchar型の配列が必要です。charで2つは必要。
「文字列」ですから、'\0'も書き込みます。
ちなみに、このままでは何百文字だろうと入力可能です。
無論、その後の動作は保証できませんが。

> 何かの本で、未使用の領域は0である確率が高いという記述をみたことがあり、'\0'は0と同じだということなので問題なく動作する率が高いのではないかと思っています。

そんな保証はないかと思いますが…
Cの規格書読んだわけではないので断言しかねますけど。

> この辺りの処理がどのような法則で実行されているのかが分かりづらくて悩んでいます。
> おそらく、
> scanf("%s", str);
> の場合には最初の文字が空白や改行文字でも、その次に有効な文字があればそれらの改行や空白を無視するのではないかと思っています。

標準ライブラリの仕様書を確認する必要があるかと思いますが…
"%s"がホワイトスペース(半角空白、水平タブ、改行)を読み飛ばす仕様になっているからではないかと。

# scanf()使わないのでなんとも…
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
暇を見つけて自分の使う関数の仕様は確認してみようと思います。

お礼日時:2007/05/26 10:07

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

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

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

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

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

QC言語 変換指定%sについてです。

現場での経験もあるPGなのですが、C言語の基礎を復習していたら疑問に思うことが出てきてしまったので、質問させて下さい。

printf関数などに使われる変換指定%sについてですが、
char word[] = "test";
char *pointer;
pointer = word;
とした場合、pointerの値は文字列wordの先頭アドレスになるので、
printf ("%x", pointer);
とすれば、そのアドレス値が表示されるのはとてもよくわかるのですが、
printf ("%s", pointer);
とした場合に、"test"と表示されるのがイマイチ納得できないんです。
printf ("%s", *pointer);
なら、まだわかるんですけど・・・

変換指定の%sというものは、
「アドレスを受け取って、受け取ったアドレスにある文字列を\0がくるまで表示する」
というものなのでしょうか?

int型のポインタで同じように
printf ("%d", pointer);
とすると、pointerの値であるアドレスが10進数表示されて、pointerが指している変数の値を表示するには、
printf ("%d", *pointer);
としなければならないわけで、そういうことをいろいろ考えていたら、収拾がつかなくなってしまって(^_^;)

「とにかく%sはそういうものなの!!」と丸暗記すれば困るようなことはないのですが、どうにもモヤモヤしっぱなしなので、%sの動きについて詳しくお分かりの方がいらっしゃいましたら、ご教授下さい。

よろしくお願いしますm(__)m

現場での経験もあるPGなのですが、C言語の基礎を復習していたら疑問に思うことが出てきてしまったので、質問させて下さい。

printf関数などに使われる変換指定%sについてですが、
char word[] = "test";
char *pointer;
pointer = word;
とした場合、pointerの値は文字列wordの先頭アドレスになるので、
printf ("%x", pointer);
とすれば、そのアドレス値が表示されるのはとてもよくわかるのですが、
printf ("%s", pointer);
とした場合に、"test"と表示されるのがイマイチ納得できないんです。
pri...続きを読む

Aベストアンサー

C言語の規格上では。
%につづく変換指定子sは空白類でない文字の並びに相当し、
長さ修飾が存在しない場合、対応する実引数は文字型配列の
先頭要素へのポインタで無ければならない
配列内の終端ナル文字の直前まで書き込み精度が指定された場合、
精度を超える書き込みは行わない。精度が指定されない場合、
または精度が配列より大きい場合その配列はナル文字を含まなければ
ならないとされています。

つまり配列より小さい精度が指定されなければ受け取ったポインタを
文字配列の先頭要素とし\0が出てくるまで表示します。

Q%P と %X の違い

アドレスを表示させるときの、%p は、%x と同じ16進数で表示される
んでしょうか?
表示の違いと言えば、大文字か小文字の違いだけなんでしょうか?
16進数の大大文字は「%X」というふうに、Xを大文字で指定すれば、
結果も大文字で表示されますよね。
%pはどういった意味なんでしょうか?



#include <stdio.h>
main()
{
char a;
short b;
printf("bのアドレスは%d,%p,%x\n", &b, &b, &b);
return 0;
}

Aベストアンサー

およそ #1 の通りで, アドレス値を出力するためには %p を使わなければなりません. %x は unsigned int を 16進で出力するという指定であり, アドレス値を出力するときに %x を使ってはいけません. 処理系によっては動いてしまうこともありますが正しいプログラムではありません.

Qint型からchar型への変換

タイトル通り、int型からchar型への変換の仕方がわかりません!><
どうしたらいいのでしょうか?

Aベストアンサー

#include <stdio.h>


char buf[5];
int no;

no = 10;
sprintf(buf, "%d", no);

Qfloat型とdouble型の変数の違いを教えてほしいです

float型とdouble型の変数の違いを教えてほしいです
2Dゲームを作っててdoubleの変数を使ってたんですが使ってはだめだと先輩に言われたんです。
理由を聞いたら、先生が「doubleは使わないほうがいい」と言われたらしくてちゃんとした理由がわかりませんでした。
それを知って何をするということではないんですが、気になって調べても出てこなかったので質問させてください。
まだゲーム作りを始めたばっかりでぜんぜん詳しくないですが教えてくれたら助かります。

Aベストアンサー

doubleとfloatでは、精度が違い、そのためメモリに占める大きさも違います。
また、一般的には、桁が多いとその分計算時間がかかります。
ですから、精度が必要ない場面では、floatを使う、というのも一つの考えかたです。

ですが、実際には「一概に言えない、処理系依存」です。

以前は全てCPUで計算していたので、精度=計算量でした。
しかし、最近では浮動小数点演算専用の回路が付いているケースが多く、計算時間は同じだったり、doubleに変換が必要でその分floatの方が遅かったり、floatでの演算はより高速にできたり、と様々です。
32bitCPUでは、32bitのfloatの方が扱いやすいでしょうが、64bitCPUでは64bitのdoubleの方が扱いやすいかもしれません。
Cのmath.hで使える標準関数はdouble型のものがほとんどです。三角関数は2Dのゲームでも使う機会が多いのではないでしょうか。sinもcosもdouble型です。内部演算は当然doubleですので、変数にfloatを使ったからと早くはならず、むしろfloat型の変数に入れるときに暗黙の型変換が発生する分遅くなる可能性もあります。

そういった背景を考え検討した結果、floatを使う方がよい、と判断したのならいいのですが、「先生に言われた」では理由になりません。
聞けるのなら、その先生に理由を聞いてください。真意がわからないうちは、鵜呑みしないことです。

doubleとfloatでは、精度が違い、そのためメモリに占める大きさも違います。
また、一般的には、桁が多いとその分計算時間がかかります。
ですから、精度が必要ない場面では、floatを使う、というのも一つの考えかたです。

ですが、実際には「一概に言えない、処理系依存」です。

以前は全てCPUで計算していたので、精度=計算量でした。
しかし、最近では浮動小数点演算専用の回路が付いているケースが多く、計算時間は同じだったり、doubleに変換が必要でその分floatの方が遅かったり、floatでの演算はより高速...続きを読む

Qバッファとは何ですか

C言語を使用してるとバッファという言葉がよく出てきますがバッファとは何ですか
メモリとは違うものですか
訳をみても緩衝材とか一時的に蓄える場所という意味でよく分かりません
一時的でない使い方も多い気がしますが実際はどういうものですか

Aベストアンサー

#1です

寝ぼけて適当に書いたので修正。

すぐ見つけることができたもので正確なものは英語版ですがこちらくらいかも。
Data buffer - Wikipedia (en.)
http://en.wikipedia.org/wiki/Data_buffer

一応簡単なものはこちらです。
バッファとは - e-Wrods
http://e-words.jp/w/E38390E38383E38395E382A1.html

「複数の機器やソフトウェアの間でデータをやり取りするときに、処理速度や転送速度の差を補うためにデータを一時的に保存しておく記憶装置や記憶領域のこと。」
が現在の基本定義です。処理速度・転送速度の差のための緩衝材的な意味です。

昔はソフトウェアとハードウェア間に使うデータでソフトウェア側がデータを受け取るか、整形して送信するときに使うメモリ領域が基本的にバッファでした。
マルチプロセッサ・マルチタスクの時代になってくると、ソフトウェア間の処理速度の違いを吸収するために使うメモリ領域にもバッファという言葉が使われるようになりました。ソフトウェア間で逐次(FIFO)処理されるデータのためのメモリ領域がこちらの使われ方の主戦場といったところでしょうか。

ソフトウェア間でただ一括転送されるデータならバッファという言葉は誤用ということになるのですが、よく誤用されます。

#1です

寝ぼけて適当に書いたので修正。

すぐ見つけることができたもので正確なものは英語版ですがこちらくらいかも。
Data buffer - Wikipedia (en.)
http://en.wikipedia.org/wiki/Data_buffer

一応簡単なものはこちらです。
バッファとは - e-Wrods
http://e-words.jp/w/E38390E38383E38395E382A1.html

「複数の機器やソフトウェアの間でデータをやり取りするときに、処理速度や転送速度の差を補うためにデータを一時的に保存しておく記憶装置や記憶領域のこと。」
が現在の基本定義です。処理速度・転送速...続きを読む

QEnterキーを押されたら次の処理に移るという事をしたい。

コンソールアプリケーション上で文字列を表示させた後、ユーザーがエンターキーを押したら次の文字列を表示するという仕様にしたいのですが、エンターキーだけ入力待ちにするっていうのはどのように書けばいいんでしょうか?

Aベストアンサー

#include <stdio.h>

int main(void)
{
char *str[] = {"abc", "def", "ghi", "jkl"};
int i;

for(i = 0; i < 4; i ++){
while(getchar() != '\n') ;
puts(str[i]);
}
return 0;
}

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) {
// ここに処理を書く
}
という関数が必要なようです。

Qc言語のポインタへの文字列入力についてです。

当方c言語初学者なのですがscanfを使ってポインタに文字列を入力したいのですがバグが発生して進みません・・・どういうことなのでしょうか?
#include <stdio.h>

int main(void)
{
char *a;

scanf("%s", a);
printf("%s", a);

return (0);
}

*aをa[128]; のように配列に変えるとうまくいくことはなんとかわかるのですが・・・助けてください(^_^;)

Aベストアンサー

ポインターというのは格納された値のアドレスのメモリーを指すための変数です。
一方、配列はデータを格納するためのメモリーを確保して、その先頭のアドレスが入っていますよ。

char *a;
scanf("%s", a);

と書くと、aを初期化せずにaの指す先にscanfで文字列を入れます。
大抵、プログラムが書き込むことを許されていないメモリーに書き込みを行おうとしたことを検出したOSからそのプログラムは強制終了されます。

char *a = "aaaaa";
scanf("%s", a);
となっているとどうなるか。
aは"aaaaa"が格納されているメモリーを指すように初期化されます。
ただ、大抵"aaaaa"は固定値を入れるために書き込みができないメモリーに格納されています。
よって、scanf("%s", a);も書き込みができないところに書こうとしたことをOSに検出され、強制終了となります。

2つ方向があると思います。
1. char a[128];のように宣言し、スタック上にメモリーを確保し、その先頭アドレスが入っているaを渡す方法。
2. mallocなどでヒープにメモリーを確保する方法。

1だと、
char a[128];
scanf("%127s", a);
のように書き、scanfで読み込んだ分をaから始まるメモリーに書くことになりますが、char a[128];で配列を確保しているので書き込みを行うことができ、強制終了はされません。

2だと、
char *a = malloc(128);
scanf("%127s", a);
printf("%s", a);
free(a);
のように書きます。
配列はスタック上に取られ、スタック上に取った値はプログラムがその関数を抜けるときに自動的に解放されますが、mallocで確保したメモリーは自動で解放されないので自分でfreeを呼んで開放する必要があります。

%127sがそろそろ気になっていると思います。
こうやって127文字までしか受け取らないようにscanfに指示しています。
C言語では文字列の最後は終了を示すNUL文字が入るので、確保したメモリーよりも1少ない値となっています。

というわけで、ちゃんとメモリーを確保してからscanfで書き込みましょう。ポインターはあくまでどこかのメモリーアドレスを指すだけで、指した先がちゃんと確保されているかどうかは知りませんから。

ポインターというのは格納された値のアドレスのメモリーを指すための変数です。
一方、配列はデータを格納するためのメモリーを確保して、その先頭のアドレスが入っていますよ。

char *a;
scanf("%s", a);

と書くと、aを初期化せずにaの指す先にscanfで文字列を入れます。
大抵、プログラムが書き込むことを許されていないメモリーに書き込みを行おうとしたことを検出したOSからそのプログラムは強制終了されます。

char *a = "aaaaa";
scanf("%s", a);
となっているとどうなるか。
aは"aaaaa"が格納されている...続きを読む

Qfgetsなどのときのstdinのバッファを消すには?

こんにちは,今C(C++でない)を使用しています。
たとえば,
char str[20]
fgets(str,sizeof(str),stdin)
としたときに20字以上を打つと,stdinのバッファに20字以上の分が残ったままになります。

C++などでは
fflush(stdin)で,うまくいきますが,普通のCでは対応がされていないみたいでうまくいきません。

よろしくお願いします。

Aベストアンサー

あ,テキスト入力だからこんな大掛かりなことしなくてもいいんだ.
末尾に'\n'が出るまで掃出せばいいんですよね.

fgets(str, sizeof(str), stdin);
if ( str[strlen(str)-1] != '\n' ){
while( getchar() != '\n' );
}

でいいんだ.失礼しました.

Q「memcpy」と「strcpy」について

C言語の初心者です。
先日、課題として以下のようなことを言われました。

「memcpyとstrcpyについて、メモリ破壊が起こるとしたら
どんな場合が考えられるか、簡単にまとめて報告してみて下さい。」
と言われました。

私にはメモリ破壊というニュアンスが分からないのですが、
どちらの関数も必要以上にコピーを行ったときに
起こるメモリ破壊ということなのでしょうか?
それとも、何か特別な意味があるのでしょうか?

C言語に詳しい方がいましたら、是非、教えて下さい。
宜しくお願いします。

Aベストアンサー

 メモリ破壊とは、「当然そこに入っているべき値」を、不用意に上書きしてしまうことです。

 たとえば、char a[100]; という宣言をしたとします。

 memcpy( a, 0, 200 );

 すると、このような実行を行った場合、変数 a の後ろにどんなメモリが存在しているのかプログラマは知ることができないのに、変数 a の後ろの未定メモリ100バイトを上書きしてしまいます。

 この未定メモリには、もしかしたら別の変数があるかもしれませんし、プログラムの一部があるかもしれません。あるいはOSのシステム領域かもしれません。
 どのみちプログラムは正常に動かなくなります。
 通常はメモリエラーが出て停止しますが、最悪の場合、メモリ上のOSを破壊してリセットするしかなくなったりもします。

 これがメモリ破壊です。


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

人気Q&Aランキング