メモリ領域を確保するとかって言うことらしいのですが、
charとかintとかで定義するのとは違うのですか?

charとかで定義した場合もメモリ領域は確保されていると思うのですが、
どこが違うのでしょうか?
違いが理解できません。

どなたか、詳しく教えてください。お願いします。

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

A 回答 (9件)

>例えばの場合のと申しますか、


>参考のソースを少し教えていただけませんか?

プログラム実行時に初めて処理人数(ninzu)が判明するシステムで、データを読み込んで処理する関数 func() を考えてみます。便宜上データの型は int で言語はCとします。本当はエラー処理(メモリが足らない場合などの)が必要ですが省略します。

void func(int ninzu)
{
  int* pData;
  intloop;

  /* 人数分の int エリアを確保 */
  pData = malloc(ninzu * sizeof(int));

  /* 人数分の int データを読み込み */
  for(loop = 0; loop < ninzu; loop ++)
  {
    *(pData + loop) = ReadData();
  }

  /*** 読みこんだデータを使って ***/
  /*** なんらかの処理&出力   ***/

/* いらなくなったエリアを開放 */
  free(pData);
}

単純化して書くとこんな感じになります。実際にはポインタ pData は単純な int へのポインタではなく構造体へのポインタだったりすることになるでしょう。これだと本当に必要なメモリだけを使うことになり、しかも人数の変動にも対応できることになります。

>こいつは"出来るな"って思われるようになるわけですね。
>他のアプリのことも考えてのプログラムって事ですね。

そうなんですが、人間がコーディングしているのでCやC++で書かれた市販されているアプリケーションでもエリア解放を忘れてしまっているプログラムがよくあります。だから同じアプリを何度も起動、終了を繰り返すと解放されないメモリが蓄積されリソース不足になってしまうやつはそういったバグを持っているということがわかります。
    • good
    • 0
この回答へのお礼

ありがとうございました。
大変分かりやすかったです。

解放忘れたりしているのが、リソース不足の原因にもなっているのですね。
気をつけなければ。
本当にありがとうございました。

お礼日時:2001/11/08 13:44

> よく変数の寿命とか分からないので、


> みんなグローバルにしていたら、COBOLかよと
> よく言われている私には苦手なトコです。

そんな、難しくないですよ。

自動変数の寿命は、変数を宣言しているところを直前で括っている中括弧の中に
いる間、が、その変数の寿命です。

int xxx()
{
  int i;
  for (i = 0 ; i < 10 ; ++i) {
    int j;
    ...
    {
      int k;
      ...
    } … kは、ここまで
  } … jは、ここまで
  return 0;
} … iは、ここまで


> みんなグローバルにしていたら、COBOLかよと

「って、COBOL やったことあるのかよ」と突っ込みを入れたくなりますよね。
今時は、COBOL を経験すること自体「まれ」ですもんね。

# といいつつも、COBOL のソースを読むはめになりそうなんですが (^^;
    • good
    • 1
この回答へのお礼

COBOLは二種情報処理技術者試験のときに
簡単だからと言う理由で
やらされました。
wark area、変数などを前もって定義しておくので
Cで言うとグローバルの考えしか出来ていないってことです。
だから、いっつもグローバルで定義しちゃうので、
スコープなんて・・・です。
でも、分かりやすかったです。
ありがとうございました。

お礼日時:2001/11/08 13:49

大きさについては既に出ている通りですが、


他に寿命(?)も違います。

グローバル変数やスタティック変数の場合は、プログラムが実行開始されてから終わるまで,
オート変数の場合,関数の処理が始まってから終わるまでが寿命となりますが、
malloc,calloc等のでとられるメモリは、プログラマが寿命を決めます。
mallocを呼んだ時に生まれ,freeを呼ばれた時に消えます。
(freeされなければ、プログラムが終わるまで)

ところで、unixの共有メモリの話がでてましたけど、
通常はsystem V系のshmget,shmatがシステムコールとして組み込まれていてそれを使いますし、
malloc系の関数はプロセス内部のメモリしか扱わないので,共有メモリの操作には使われないと思いますが。

この回答への補足

変数の寿命を考えることが出来るのですね。

ということは普通にintなどと定義したときよりは
資源が有効に使えるんですね。

よく変数の寿命とか分からないので、
みんなグローバルにしていたら、COBOLかよと
よく言われている私には苦手なトコです。

補足日時:2001/10/31 10:32
    • good
    • 0

#5の者です。



>Windows のメモリは使われてないとこだらけになって

別に Windows というわけではないですね。失礼しました。(^^;
    • good
    • 0

allocとは要素の数が決まってない場合に使うものです。



たとえば
1)個数が全く予測の出来ない場合
2)通常は10個分ぐらいあればいいけど、ある条件の時には100万個必要になる。

1)の場合は
int nantoka[100]; ってやったんじゃまずいのは分かりますよね? 1000 だって 10000 だってまずいですよ。

2)の場合
常に100万個分のエリアを確保するとものすごく無駄ですよね。
int nantoka[1000000];

allocを使用すればその都度必要な分だけを確保することができて、いらなくなったら削除できるので無駄がなくなるわけです。十分に大きいエリアを最初から取っとけばいいじゃんというコーディングをみんながしたら Windows のメモリは使われてないとこだらけになってすぐにメモリが足りなくなりますよ。(^^;

この回答への補足

回答ありがとうございます。

無駄が無くなる。
こいつは"出来るな"って思われるようになるわけですね。
他のアプリのことも考えてのプログラムって事ですね。

例えばの場合のと申しますか、
参考のソースを少し教えていただけませんか?
どのように定義するのだとかということなども。
お願い致します。

補足日時:2001/10/31 10:18
    • good
    • 0

> allocとか使わなくても


> 最初から大きいサイズを用意しておくということでも良いのですよね。

これは、ある意味正解です。

ただし、その大きいサイズを用意するのが無駄すぎる、とか、実メモリが少ない
環境でもそこそこ動いて欲しい(*)場合なんかには、できないアプローチです
よね。

  (*) 一杯メモリが積んであるならば、画像を同時に100枚でも処理できるが、
    同時に2枚までの処理で良いから、少ないメモリのマシンでも動いてほしい、とか

> でも、いまいちよく理解できませんでした。

ん~、力不足(私が、ね)。

プログラムの動作時に大きさを変えられるかどうか、って違いがあることはOK
なんですよね。

であれば、今は、その程度の理解でも良いかも。

「スタック」とか「ヒープ」とかっていう言葉に遭遇してから、理解を深めても
十分。

この回答への補足

ありがとうございます。
一歩進みました。

実際にサイズが変化するようなものに
であったことが無かっただけにイメージが湧きませんでした。
プラスして、実装メモリなんてモノも全く気にしていませんでした。

allocとかが使えるようになると、PC資源の
有効利用ができるって言うことですよね。

補足日時:2001/10/31 10:15
    • good
    • 0

失礼しました。


APとはアプリケーションの略で使いました。

UNIXでは共有メモリという考えでよく使用されるのですが、
例えばA、Bという二つのアプリケーション(以下AP)があるとします。

Aでメモリ領域を確保しその領域に"あいう"と書き込むとします。
Bでそのメモリ領域を参照し"あいう"を取得する場合には、
メモリ領域の確保にalloc系の関数が使用されます。(malloc、globaalloc等々)
伝わりましたでしょうか…。
    • good
    • 0

char等の変数宣言もalloc系関数も、


メモリを確保するという点では変わらないのですが、

変数宣言した場合は宣言したAPからしかそのメモリ領域を利用できないのに対して、
alloc系関数では他のAPからでもその領域にアクセスできるという違いがあります。

この回答への補足

APってなんでしょうか?
アプリ?アクセスポイント?
教えていただけませんか?

補足日時:2001/10/30 18:03
    • good
    • 0

> メモリ領域を確保するとかって言うことらしいのですが、


> charとかintとかで定義するのとは違うのですか?

違います。

「欲しいサイズのメモリを使えるようにする」という意味では、ほとんど差が無い
のですが、その用意の仕方が違います。

変数で宣言する場合には、あらかじめソースを書く段階で、型とその大きさ(配列の
個数)が決っていなければなりません。

それだけで、不自由が無ければそれで良いのですが、実際には、プログラムを動かして
いるときに、初めてその大きさが決まり、そのサイズのメモリが欲しい、というときが
あります。

その場合には alloc 系の関数を使うしかないです。

と言いつつも、新しい C の規格(C99)では、alloc 系の関数を使わなくても、大きさを
後から決められる配列が使えたりします。

★こんなソースがかけちゃう!

int size;
scanf("%d", &size);

int data[size]; /* おおっと! */

/* 今までの C では、こう書くしかなかったんです。
int size;
int *data;

scanf("%d", &size);

data = malloc(size * sizeof(int));
*/


後、細かいことを言うと、変数の宣言で用意されるメモリの場所と、alloc 系の関数で
用意される場所が微妙に(それぞれの中でもやり方によって)違います。まあ、この
あたりは、もっと突っ込んだことをやるようになってから覚えてもいいでしょう。

この回答への補足

回答ありがとうございます。
でも、いまいちよく理解できませんでした。
大変申し訳ありませんが、
さらに、詳しく(無理だとは思いますが、)お願いできませんでしょうか?

なんとなくでは、分かってきたんですが
分かった・分からないかと聞かれた場合に分からないとなってしまいますもので。

何処が分からないかと言うと、イメージが湧きにくいというのも
有ると思うのですが、allocとか使わなくても
最初から大きいサイズを用意しておくということでも良いのですよね。

よろしくお願いいたします。

補足日時:2001/10/30 18:21
    • good
    • 0

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

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

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

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

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

Qchar型+char型ってint型? if(char型==int型)?

C言語の「汎整数拡張(インテグラルプロモーション)」というものに関するものだと思います。

char型とchar型を加えた結果は、char型でしょうか。それともint型でしょうか。
(下のプログラムの
printf("sizeof(a[0]+a[1])は%d\n", sizeof(a[0]+a[1])); /* char型+char型 */
という部分の結果は4なので、int型と考えるべきなのかな。)

私は、char型とint型の加算の結果はint型だと思っていましたが、
char型とchar型の加算の結果はやはりchar型だと思っていました。
(それが間違えているのでしょうか。)


if(a[0]==i) /* char型とint型の比較(?) */
の部分では、左辺はchar型、右辺はint型ですが、このように型の違う変数を比較しても文法上構わないのでしょうか。
(私は、「比較は必ず型の同じもの同士でしかできない」と思っていました。)
左辺はchar型のように見えて、じつはint型ですか。


#include <stdio.h>
int main(void)
{
char a[4];
int i=77;
printf("sizeof(int)は%d\n", sizeof(int));
printf("sizeof(char)は%d\n", sizeof(char));
printf("sizeof('M')は%d\n", sizeof('M'));
printf("sizeof(a[0])は%d\n", sizeof(a[0]));

a[0]='M';
a[1]=7+6;
a[2]=a[0]+a[1];
printf("sizeof(a[0]+a[1])は%d\n", sizeof(a[0]+a[1])); /* char型+char型 */
printf("sizeof(+a[0])=%d\n", sizeof(+a[0]));

if(a[0]==i) /* char型とint型の比較(?) */
puts("a[0]==i");
else
puts("a[0]!=i");

return(0);
}

ちなみにワーニングもエラーもなんにもでません。

C言語の「汎整数拡張(インテグラルプロモーション)」というものに関するものだと思います。

char型とchar型を加えた結果は、char型でしょうか。それともint型でしょうか。
(下のプログラムの
printf("sizeof(a[0]+a[1])は%d\n", sizeof(a[0]+a[1])); /* char型+char型 */
という部分の結果は4なので、int型と考えるべきなのかな。)

私は、char型とint型の加算の結果はint型だと思っていましたが、
char型とchar型の加算の結果はやはりchar型だと思っていました。
(それが間違えているのでしょう...続きを読む

Aベストアンサー

「sizeof 単項式」について補足です。

これは sizeof 演算子が「単項演算子」であるために書かれたものだと思われます。
例えば同様に単項演算子である ++ も、「++ 単項式」です。

では単項式とは何なのかというと、これは以下のようなものを指します。(抜けがあるかもしれませんが。)
・定数
・名前(変数名や関数名など)
・( 式 )
・後置式

( 式 ) はおなじみの「式の結果を返す」ものですが、実はこれ全体で単項式です。
本来「sizeof 単項式」では ( ) を必要としないので、sizeof より優先順位の低い演算子を含む式を裸で渡すことはませんが、( ) で囲めばどんな式でも書けるわけです。

後置式は「配列構文によるアドレス参照式」や「関数呼び出し式」、「メンバ参照式」「後置型インクリメント/デクリメント式」です。
なので、
> sizeof(a[0])
> と書いたら、[ ] という演算子は2項演算子だから、a[0]は単項式になっていない
は、わざわざ ( ) で囲まず sizeof a[0] と書いても、正しい単項式なので問題ありません。
(これらの演算子は、全て sizeof より優先順位が上になっています。)

先に ++ も単項式を取る、ということを書きましたが、++ だって
  ++*(p + n)
のような記述が通るのだから、sizeof でも問題がなくて当然です。

また、例えば ++ では「オペランドは左辺値でなければならない」という原則があり、左辺値でない式に ++ を適用するとコンパイルエラーが発生します。
しかし、sizeof に「オペランドはオブジェクトでなければならない」などという原則を聞いたことがありません。
無論コンパイルエラーも起きませんし、期待通りに式の値のサイズが返ります。
「式の値のサイズ」というのはコンパイル時に判明しているものなので、取得できて当然といえば当然ですが、これがCで定められた仕様かどうかというのは残念ながら見つけることはできませんでした。
ただし、質問にあるような sizeof の文法は全て正しく、警告が出ないのは仕様通りだというのは間違いありません。

「sizeof 単項式」について補足です。

これは sizeof 演算子が「単項演算子」であるために書かれたものだと思われます。
例えば同様に単項演算子である ++ も、「++ 単項式」です。

では単項式とは何なのかというと、これは以下のようなものを指します。(抜けがあるかもしれませんが。)
・定数
・名前(変数名や関数名など)
・( 式 )
・後置式

( 式 ) はおなじみの「式の結果を返す」ものですが、実はこれ全体で単項式です。
本来「sizeof 単項式」では ( ) を必要としないので、sizeof より優...続きを読む

Qintやshortやcharの変数確保時間

for文などでよく一時変数に

for ( int i=0; ・・・
とか
for ( short s=0; ・・・
とか
for ( char i=0; ・・・

みたいに整数型の変数が使われます。

確か変数の表せる範囲は
long>int>short>char
だったと思うのですが、変数を確保する時間やメモリサイズに違いはあるのでしょうか?
たとえばlong型変数を10万個確保する時間とintとかshortとかcharのそれ
とは違いがあるのかなぁと疑問に思いました。

Aベストアンサー

一時変数の話ですよね?

「i386系の処理系で、一時変数に限定した話」であれば「どんな変数であっても、確保は一瞬で行われる」ので、型やサイズや個数が違っても、何の変わりもありません。

i386系では「一時変数はスタックに作られる」ので「確保動作は、CPUのSPレジスタを必要なだけ減算するのみ」で「全ての変数が一気に確保」されます。

例えば、ある関数をi386系のCPU用にコンパイルすると、アセンブラでは

 push ebp      ;BPレジスタをスタックに退避
 mov ebp,esp    ;現在のSPレジスタをBPレジスタにコピー
 add esp,-0x10244 ;66116バイト分の一時変数を一気に確保
 (ここから関数の中身)
 mov esp,ebp    ;SPレジスタを元に戻し、一気に全部の変数を解放
 pop ebp       ;BPレジスタをスタックから復帰
 ret          ;呼び出し元に帰る

となります。

このように「確保も解放も、1命令」で終ってます。

Q44行目: パラメータ '__format' は const signed char * 型として定義されているので int は渡せない(関数 main )

たびたび、Cについてご質問させて頂いていますが件名のようなエラーで行き詰まっています。

内容は、textファイルを読み込み、htmlファイルを生成するといったものです。成績管理みたいなことをしたいと考えています。とりあえず、44行目に
fprintf(file ,seito[i].val[0]);
で数(1)の点数をHTMLに書き込みたいのですが、
件名のエラーが表示されうまくコンパイルができない状態です。お助けくださいませ。よろしくお願いいたします。

Aベストアンサー

fprintfは、引数として
ファイルポインタ、出力書式文字列、変数並び
をとります。
質問文の場合、出力書式文字列がありません。
"%d"のような感じで書きます。

出力書式については、調べてみて下さい。

Q44行目: パラメータ '__format' は const signed char * 型として定義されているので int は渡せない(関数 main )

☆--------------ソース--------------☆
#include <stdio.h>

struct seiseki {
int no;
char fname[20];
char lname[20];
int val[3];
}seito;

int main(void)
{
int i,total;
FILE *fp;
FILE *file;
struct seiseki seito[20];
char buf[1024];
fp = fopen("in.txt", "r");
i=0;
while( fgets(buf, sizeof(buf), fp) ){
struct seiseki tmp;
sscanf(buf,"%d %s %s %d %d %d",&tmp.no,tmp.lname,tmp.fname,&tmp.val[0],&tmp.val[1],&tmp.val[2]);
seito[i++] = tmp;
}
printf("ID / NAME / 数(1) / 数(2) / 数(3) \n");
for(i = 0; i < 3; i++) {
printf("%d / %s %s / %d / %d / %d\n",
seito[i].no,seito[i].lname,seito[i].fname, seito[i].val[0], seito[i].val[1], seito[i].val[2]);

}
file = fopen("output.html","w");
fprintf(file ,"<HTML><HEAD></HEAD><BODY><table border=1 bodercolor=black cellspacing=0 width=700>\n");
fprintf(file ,"<tr bgcolor=#FF7575><td>ID</td><td>氏名</td><td>数(1)</td><td>数(2)</td><td>数(3)</td><td>合計点</td><td>平均点</td><td>偏差値</td><td>順位</td></tr>\n");
for(i = 0; i < 3; i++) {
fprintf(file ,seito[i].lname);
fprintf(file ,seito[i].fname);
☆省略☆
fprintf(file ,seito[i].val[0]);
☆省略☆

}
fprintf(file ,"\n</table></BODY></HTML>\n");
return 0;
}

☆--------------ソース--------------☆
#include <stdio.h>

struct seiseki {
int no;
char fname[20];
char lname[20];
int val[3];
}seito;

int main(void)
{
int i,total;
FILE *fp;
FILE *file;
struct seiseki seito[20];
char buf[1024];
fp = fopen("in.txt", "r");
i=0;
while( fgets(buf, sizeof(buf), fp) ){
struct seiseki tmp;
sscanf(buf,"%d %s %s %d %d %d",&tmp.no,tmp.lname,tmp.fname,&tmp.val[0],&tmp.val[1],&tmp.val[2]);
seito[i++] = tmp;
}
printf("I...続きを読む

Aベストアンサー

fprintf(file ,seito[i].val[0]);を
fprintf(file ,"%d",seito[i].val[0]);
にしてみて下さい。

Qint main(int argc, char* argv[]) についての質問

こんにちは.つね日ごろ思っている質問させてください.
Cの参考書には,
(1)
void main(void)
{
}

(2)
int main(int argc, char* argv[])
{
return 0;
}
の2つのパターンが記載されていますが,
どういう違いがあるのでしょうか?

(1)の場合main関数は,型を持たず,引数も持たない.
※Turbo Cなどのコンパイラーでは,
return文がないと警告出ます.
(2)の場合は,int 型をかえし,引数はint型 変数と char型ポインタ配列(?)
を指定している.
といったくらいしか分かりません.

(2)に関してもう少し述べれば,
コマンドラインからファイルを指定し,実行することが
できると勉強した記憶があるのですが,
理解があいまいです.

特に(2)の場合のmain関数の意味と,その使い方について
アドバイスお願い致します.

Aベストアンサー

> (1)
> void main(void)
  ...
> (2)
> int main(int argc, char* argv[])
  ...
> の2つのパターンが記載されていますが,どういう違いがあるのでしょうか?

(1) は、間違いです。少なくとも ANSI-C の規格に合致していません。

main() は、特別な関数で、ANSI-C の規格では以下の三通りのうちのどれか
でなくてはいけない、と定められています。

int main(void)
int main(int argc, char *argv[]);
int main(int argc, char *argv[], char *envp[]);

因みに三番目の形式では、三つ目の引数には環境変数が入ります。
以下のようなコードで確認ができます。

int main(int argc, char *argv[], char *envp[])
{
  int i = 0;
  while (envp[i]) {
    printf("envp[%d] = '%s'\n", i, envp[i]);
    ++i;
  }
  return 0;
}


> ※Turbo Cなどのコンパイラーでは,return文がないと警告出ます

Turbo C は、規格に厳格なのでしょう。返り値が void なのはおかしいので、
int だとみなすよ、という警告も出てるはず。で、int が帰り値だとみなし
ているので return が無いと、返り値が不定になるよ、と警告を出している
のでしょう。

> (1)
> void main(void)
  ...
> (2)
> int main(int argc, char* argv[])
  ...
> の2つのパターンが記載されていますが,どういう違いがあるのでしょうか?

(1) は、間違いです。少なくとも ANSI-C の規格に合致していません。

main() は、特別な関数で、ANSI-C の規格では以下の三通りのうちのどれか
でなくてはいけない、と定められています。

int main(void)
int main(int argc, char *argv[]);
int main(int argc, char *argv[], char *envp[]);

因みに三番目の形式では、三...続きを読む


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

人気Q&Aランキング

おすすめ情報