Cプログラムを使用してユーザーからの入力を読み取りたい。のような配列を使いたくない、
char names[50];
ユーザーが長さ10の文字列を指定すると、残りのスペースが無駄になるためです。
次のような文字ポインタを使用すると、
char *names;
そのような方法でメモリを割り当てる必要があります
names = (char *)malloc(20 * sizeof(char));
この場合も、メモリが浪費される可能性があります。
したがって、必要なのは、文字列の長さとまったく同じ文字列にメモリを動的に割り当てることです。
仮定してみましょう、
ユーザー入力が"stackoverflow"
の場合、割り当てられるメモリは14
である必要があります(つまり、文字列の長さ= 13および '\ 0'の追加スペース1つ)。
どうすればこれを達成できますか?
一度に1文字ずつ(getc(stdin)
を使用して)読み取り、文字列(realloc
)を増やしていきます。
少し前に書いた関数を次に示します。テキスト入力のみを目的としていることに注意してください。
char *getln()
{
char *line = NULL, *tmp = NULL;
size_t size = 0, index = 0;
int ch = EOF;
while (ch) {
ch = getc(stdin);
/* Check if we need to stop. */
if (ch == EOF || ch == '\n')
ch = 0;
/* Check if we need to expand. */
if (size <= index) {
size += CHUNK;
tmp = realloc(line, size);
if (!tmp) {
free(line);
line = NULL;
break;
}
line = tmp;
}
/* Actually store the thing. */
line[index++] = ch;
}
return line;
}
10個の要素で始まる配列を作成できます。文字ごとに入力を読み取ります。終わったら、さらに5つを再割り当てします。最高ではありませんが、後で他のスペースを解放できます。
正規表現、たとえば次のコードを使用することもできます。
char *names
scanf("%m[^\n]", &names)
stdinから行全体を取得し、必要なスペースを動的に割り当てます。その後、もちろんnames
を解放する必要があります。
メモリを節約する必要がある場合は、charごとにcharを読み取り、毎回再割り当てします。パフォーマンスは低下しますが、この10バイトを節約できます。
別の良いトレードオフは、関数を(ローカル変数を使用して)読み込んでからコピーすることです。したがって、大きなバッファーは関数スコープになります。
以下は、動的な文字列を作成するためのコードです。
void main()
{
char *str, c;
int i = 0, j = 1;
str = (char*)malloc(sizeof(char));
printf("Enter String : ");
while (c != '\n') {
// read the input from keyboard standard input
c = getc(stdin);
// re-allocate (resize) memory for character read to be stored
str = (char*)realloc(str, j * sizeof(char));
// store read character by making pointer point to c
str[i] = c;
i++;
j++;
}
str[i] = '\0'; // at the end append null character to mark end of string
printf("\nThe entered string is : %s", str);
free(str); // important step the pointer declared must be made free
}
char* load_string()
{
char* string = (char*) malloc(sizeof(char));
*string = '\0';
int key;
int sizer = 2;
char sup[2] = {'\0'};
while( (key = getc(stdin)) != '\n')
{
string = realloc(string,sizer * sizeof(char));
sup[0] = (char) key;
strcat(string,sup);
sizer++
}
return string;
}
int main()
{
char* str;
str = load_string();
return 0;
}
reallocはかなり高価なアクションです...文字列を受け取る私の方法は次のとおりです、reallocの比率は1:1ではありません:
char* getAString()
{
//define two indexes, one for logical size, other for physical
int logSize = 0, phySize = 1;
char *res, c;
res = (char *)malloc(sizeof(char));
//get a char from user, first time outside the loop
c = getchar();
//define the condition to stop receiving data
while(c != '\n')
{
if(logSize == phySize)
{
phySize *= 2;
res = (char *)realloc(res, sizeof(char) * phySize);
}
res[logSize++] = c;
c = getchar();
}
//here we diminish string to actual logical size, plus one for \0
res = (char *)realloc(res, sizeof(char *) * (logSize + 1));
res[logSize] = '\0';
return res;
}
これは、ユーザー入力から文字列をスキャンし、その文字列をユーザー入力と同じサイズの配列に格納するために作成した関数スニペットです。 '\ 0'文字を格納できるように、jを値2に初期化することに注意してください。
char* dynamicstring() {
char *str = NULL;
int i = 0, j = 2, c;
str = (char*)malloc(sizeof(char));
//error checking
if (str == NULL) {
printf("Error allocating memory\n");
exit(EXIT_FAILURE);
}
while((c = getc(stdin)) && c != '\n')
{
str[i] = c;
str = realloc(str,j*sizeof(char));
//error checking
if (str == NULL) {
printf("Error allocating memory\n");
free(str);
exit(EXIT_FAILURE);
}
i++;
j++;
}
str[i] = '\0';
return str;
}
Main()では、別のchar *変数を宣言してdynamicstring()の戻り値を格納し、使用が終了したらそのchar *変数を解放できます。
以下は、同じ機能を実行するスニペットです。
このコードは Kunal Wadhwa によって書かれたものに似ています。
char *dynamicCharString()
{
char *str, c;
int i;
str = (char*)malloc(1*sizeof(char));
while(c = getc(stdin),c!='\n')
{
str[i] = c;
i++;
realloc(str,i*sizeof(char));
}
str[i] = '\0';
return str;
}
まず、(入力の構造に応じて)入力を読み取り、使用するスタック内のメモリを意味する文字列を格納する新しい関数を定義します。文字列の長さを入力に十分な長さに設定します。
次に、strlen
を使用して、以前に保存された文字列の正確な使用長を測定し、malloc
を使用して、strlen
で定義されるヒープ内のメモリを割り当てます。コードを以下に示します。
int strLength = strlen(strInStack);
if (strLength == 0) {
printf("\"strInStack\" is empty.\n");
}
else {
char *strInHeap = (char *)malloc((strLength+1) * sizeof(char));
strcpy(strInHeap, strInStack);
}
return strInHeap;
最後に、strInStack
の値をstrInHeap
を使用してstrcpy
にコピーし、strInHeap
へのポインターを返します。 strInStack
は、このサブ関数でのみ終了するため、自動的に解放されます。
これはより単純なアプローチです
char *in_str;
in_str=(char *)malloc(512000 * sizeof(char));
scanf("\n%[^\n]",in_str);