如何使用 realloc 重新分配另一个大小

How to realloc another size with realloc

我有一个程序将名称作为输入,如果输入小于允许的大小,它将保存在指针中。

如果输入大于允许的大小,则将使用 realloc 函数来满足所需的内存。 此时的程序只分配了 6 个字节,5 个用于名称 MICHI,1 个用于 '\0'。 如果用户键入 MICHAEL,则程序会为该指针分配足够的内存以适应该指针内的 MICHAEL

程序如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct person{
    char *name;
}pers;

void addMem(void){
    unsigned int length = 6;
    size_t newLength = 0;
    unsigned int newSize = 0;
    unsigned int i =0;
    char *name;
    int c;

    name = malloc(lenght);
    if(name == NULL){
        exit(1);
    }
    newSize = length;

    printf("Enter your name:>  ");

    while ((c = getchar()) != '\n' && c!=EOF){
        name[i++]=(char)c;

        if(i == newSize){
            newSize = i+length;
            name = realloc(name, newSize);
        }
    }

    name[i] = '[=10=]';

    newLength = strlen(name)+1;
    pers.name = malloc(newLength);

    memcpy(pers.name, name, newLength);

    free(name);
    name = NULL;
}

int main(void){
    addMem();

    printf("Your name is:>  %s\n",pers.name);
    free(pers.name);
    pers.name = NULL;
    return 0;
}

程序运行良好,但我需要以某种方式使 realloc() 仅提供最大内存大小,因为此时它会重新分配,直到用户按下 ENTER。

这意味着我有 6 字节用于 Michi5 + 1 用于 '\0') 并且最大尺寸应该是 8 (7 for Michael 1'\0').

我该怎么做?

编辑:

希望你现在明白了。

我的程序只接受带有 5 个字母的名字。 在某些时候,我决定可能程序应该接受最大 10 个字母的名称。 我已经为 5 (michi) 分配了内存。 如果您键入 Michael,我们有 7 个字母,因此程序应该为 Michael 分配另外两个字母。 但是如果我输入 Schwarzernegger,那么这个名字太长了我不接受它所以我需要让我的程序只为迈克尔分配内存。

您对应该获得多少内存的计算是错误的。 (正如@dbush 在评论中所说,这很好,因为您在 6 bytes 的块中分配内存,这比按字节分配 更有效)

无论如何,要将以 6 字节为单位分配的行为更改为以字节为单位分配,请执行以下操作:

while ((c = getchar()) != '\n' && c != EOF) {
    name[i++] = (char) c;

    /* added IF requests on comments */
    if (i > 7) {
        printf("Names longer than 7 not allowed!\n");
        name[7] = 0x0;
        break;
    }
    else if (i >= length) 
        name = realloc(name, newSize);
}

将打印:

$ ./draft
Enter your name:>  Michael
reallocing 7
reallocing 8
Your name is:>  Michael

$ ./draft
Enter your name:>  Whosebug          
reallocing 7
reallocing 8
reallocing 9
reallocing 10
reallocing 11
reallocing 12
reallocing 13
reallocing 14
Your name is:>  Whosebug

$ ./draft
Enter your name:>  Michi
Your name is:>  Michi

阅读更多

正如所说,你最好分配一个大内存块并尽可能少地使用realloc。第二个 link 支持这一点。它还建议您应该使用 第二个循环 来计算您需要的大小,因此您只需要调用 malloc 一次。

让我们分解您的主循环:

unsigned int length = 6;
unsigned int newSize = 0;

name = malloc(length);
...
newSize = length;

while ((c = getchar()) != '\n' && c!=EOF){
    name[i++]=(char)c;

    if(i == newSize){
        newSize = i+length;
        name = realloc(name, newSize);
    }
}

您开始为 name 分配 6 个字节。这对于 5 个字符加上一个 NULL 字节是好的。然后,对于您阅读的每个字符,您将其添加到 name 的末尾。

在每次迭代中,您检查输入的字符数是否等于分配的缓冲区大小。如果是这样,您 realloc 缓冲区并添加 6 个字节,所以现在它长 12 个字节。

然后您继续阅读更多字符。如果你发现你输入了 12 个字符,你 realloc 6 个字节,所以现在 name 是 18 个字节长。

这是一个很好的方法。通过这种方式,您分配了足够的内存来容纳用户输入的任何内容,最多分配了 5 个额外的字节。因此无需将名称限制为 7 个字节或任何其他特定数字。您可以添加一个检查,说明如果字符总数超过 7 个字节,则打印错误并退出,但似乎没有任何理由这样做。

编辑:

如果名称永远不会超过 7 个字节,您可以这样做而不是 mallocrealloc for name:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct person{
    char *name;
}pers;

void addMem(void){
    unsigned int i = 0;
    char name[8];
    int c;

    printf("Enter your name:>  ");

    while ((c = getchar()) != '\n' && c!=EOF){
        name[i++]=(char)c;

        if(i == sizeof(name)){
            printf("name too long\n");
            pers.name = NULL;
            return;
        }
    }

    name[i] = '[=11=]';

    pers.name = malloc(strlen(name)+1);
    strcpy(pers.name, name);
}

int main(void){
    addMem();

    printf("Your name is:>  %s\n",pers.name);
    free(pers.name);
    pers.name = NULL;
    return 0;
}

这样,读取名称的内部缓冲区是固定大小的,当您完成读取名称后,您仍然分配足够的 space 来将字符串复制到 pers.name

作为Enzo的答案在7个字母后停止你可以使用。

while ((c = getchar()) != '\n' && c != EOF) {
name[i++] = (char) c;

if (i >= length) {
    if(i+1<=7)
       name = realloc(name, i + 1);
    else
       {
          //generate error message
       }
}
}