web-dev-qa-db-ja.com

文字列にメモリ空間を動的に割り当て、ユーザーからその文字列を取得する方法は?

Cプログラムを使用してユーザーからの入力を読み取りたい。のような配列を使いたくない、

char names[50];

ユーザーが長さ10の文字列を指定すると、残りのスペースが無駄になるためです。

次のような文字ポインタを使用すると、

char *names;

そのような方法でメモリを割り当てる必要があります

names = (char *)malloc(20 * sizeof(char));

この場合も、メモリが浪費される可能性があります。

したがって、必要なのは、文字列の長さとまったく同じ文字列にメモリを動的に割り当てることです。

仮定してみましょう、

ユーザー入力が"stackoverflow"の場合、割り当てられるメモリは14である必要があります(つまり、文字列の長さ= 13および '\ 0'の追加スペース1つ)。

どうすればこれを達成できますか?

42
Dinesh

一度に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;
}
42
cnicutar

10個の要素で始まる配列を作成できます。文字ごとに入力を読み取ります。終わったら、さらに5つを再割り当てします。最高ではありませんが、後で他のスペースを解放できます。

6
tekknolagi

正規表現、たとえば次のコードを使用することもできます。

char *names
scanf("%m[^\n]", &names)

stdinから行全体を取得し、必要なスペースを動的に割り当てます。その後、もちろんnamesを解放する必要があります。

5
Jytug

メモリを節約する必要がある場合は、charごとにcharを読み取り、毎回再割り当てします。パフォーマンスは低下しますが、この10バイトを節約できます。

別の良いトレードオフは、関数を(ローカル変数を使用して)読み込んでからコピーすることです。したがって、大きなバッファーは関数スコープになります。

5
BigMike

以下は、動的な文字列を作成するためのコードです。

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
}
3
Kunal Wadhwa
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;
  }
1
Shihan

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
Omer

これは、ユーザー入力から文字列をスキャンし、その文字列をユーザー入力と同じサイズの配列に格納するために作成した関数スニペットです。 '\ 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 *変数を解放できます。

0
André Fael

以下は、同じ機能を実行するスニペットです。

このコードは 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;
}
0
user8311083

まず、(入力の構造に応じて)入力を読み取り、使用するスタック内のメモリを意味する文字列を格納する新しい関数を定義します。文字列の長さを入力に十分な長さに設定します。

次に、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は、このサブ関数でのみ終了するため、自動的に解放されます。

0
Edward Xu

これはより単純なアプローチです

char *in_str;
in_str=(char *)malloc(512000 * sizeof(char));
scanf("\n%[^\n]",in_str);
0
Kiran JD