1バイトを無駄にせずに5つの名前を保存したいので、mallocを使用してメモリを割り当てるにはどうすればよいですか?
8 に答える
これはすべての実用的な目的では不可能であり、malloc
多くの場合、要求されたよりも大きいメモリのブロックを返します。
#include <stdio.h>
#include<stdlib.h>
int main()
{
int n,i,c;
char *p[5];/*declare a pointer to 5 strings for the 5 names*/
for(i=0;i<5;i++)
{
n=0;
printf("please enter the name\n" );/*input name from the user*/
while((c=getchar())!='\n')
n++;/*count the total number of characters in the name*/
p[i]= (char *)malloc(sizeof(char)*n);/*allocate the required amount of memory for a name*/
scanf("%s",p[i]);
}
return 0;
}
5つの名前の累積の長さがわかっている場合は、それlength_names
を呼び出しましょう。
void *pNameBlock = malloc(length_names + 5);
次に、名前をnullで終了し(+5はnullで終了します)、。が指すメモリに次々に保存できますpNameBlock
。
char *pName1 = (char *) pNameBlock;
名前データを*pName1に保存します。たぶん経由
char *p = *pName1;
あなたはバイトごとに書くことができます(以下は疑似コードです)。
*p++ = byte1;
*p++ = byte2;
等
ヌル終了で終了します:
*p++ = '\0';
今設定
char *pName2 = p;
上記のように、を使用して2番目の名前を記述しp
ます。
この方法で物事を行うと、まだいくらかのメモリを浪費します。Mallocは、内部で要求しているよりも多くのメモリを取得しますが、この1回の操作で、この1つのブロックを取得し、これを超えるオーバーヘッドが発生することなく、そのメモリを1回だけ浪費します。
ただし、この方法では、名前にchar *
、などのsをfree()することはできないため、十分に注意してください。pName1
一度だけ取得したポインタを1つだけ解放できますpNameBlock
。
興味を持ってこの質問をしている場合は、わかりました。しかし、あなたがこの記憶に制約がある場合、あなたは非常に非常に苦労するでしょう。mallocはメモリをいくらか浪費しますが、それほど多くはありません。この制約のあるCで作業するのは難しいでしょう。あなたはほとんどあなた自身の超軽量メモリマネージャを書かなければならないでしょう(あなたは本当にそれをしたいですか?)。それ以外の場合は、1バイトも無駄にする余裕がない場合は、アセンブリで作業する方がよいでしょう。
どんな種類の超窮屈な組み込みシステムがこの種のメモリ使用量の制限を課すのか想像するのに苦労しています。
名前を格納するためにバイトを無駄にしたくない場合は、Cでdouble配列(char)を動的に割り当てる必要があります。
Cのdouble配列は、ポインターのリストへのポインターとして実装できます。
char **name; // Allocate space for a pointer, pointing to a pointer (the beginning of an array in C)
name = (char **) malloc (sizeof(char *) * 5); // Allocate space for the pointer array, for 5 names
name[0] = (char *) malloc (sizeof(char) * lengthOfName1); // Allocate space for the first name, same for other names
name[1] = (char *) malloc (sizeof(char) * lengthOfName2);
....
これで、名前の長さが異なる場合でも、スペースを追加せずに、名前を配列内の対応する位置に保存できます。
ダブルポインタの概念を採用し、ポインタアドレスをインクリメントして名前を1文字ずつ入力する必要があります。そうすれば、5つの名前すべてを保存して、メモリを節約できます。
しかし、プログラマーとして、このタイプの面倒なタスクを使用する必要はありません。名前を格納するためにポインターの配列を取得し、メモリを段階的に割り当てる必要があります。これは名前の保存の概念のみを対象としていますが、大量のデータを処理する場合は、リンクリストを使用してすべてのデータを保存する必要があります。
「メモリの浪費」とは何ですか?それを明確に定義できれば、解決策を見つけることができます。
たとえば、nullで終了する文字列のnullは、nullが出力されないため、「無駄なメモリ」と見なされる場合があります。ただし、他の人はそれがないと2番目のアイテム(文字列の長さ)を保存する必要があるため、メモリの浪費とは見なさない可能性があります。
バイトを使用すると、そのバイトは完全に使用されます。そのバイトなしでそれがどのように行われるかを私に示すことができる場合にのみ、私はあなたのメモリ浪費の主張が有効であると見なします。文字列の最後にnullを使用します。文字列の配列を宣言する場合は、その配列も使用します。必要なものを作成し、それらのアイテムを再配置してより少ないメモリを使用できることがわかった場合は、他の方法でメモリを浪費することを決定します。それまでは、まだ終わっていない夢を追いかけています。
これらの5つの「名前」がアセンブリジャンプポイントである場合、それらを保持するために完全な文字列に相当するメモリは必要ありません。5つの「名前」がブロックスコープの変数である場合、おそらくレジスタがすでに提供している以上のメモリは必要ありません。文字列の場合は、文字列を組み合わせてオーバーレイすることができます。ただし、解決策と、最初の解決策を比較するための2番目の解決策を考え出すまでは、メモリの浪費/節約のケースはありません。
ブロックをmallocすると、実際には、要求したよりも少し多くのメモリが割り当てられます。この追加メモリは、割り当てられたブロックのサイズなどの情報を格納するために使用されます。
名前をバイナリでエンコードし、バイト配列に格納します。