使用指针和realloc添加新记录

时间:2014-12-01 04:03:57

标签: c pointers dynamic

Hey Guys所以基本上我正在编写一个程序,在那里你提示用户他想要存储多少个名字。然后根据他的响应创建指针。之后,你提示他要向指针添加多少个名字。所以基本上我试图通过使用realloc来扩展相同的阵列,但我不确定我是否正确使用它(显然不是因为它不起作用) 基本上我希望用户已经输入的名字按原样保留,并且程序开始向用户询问他想要输入的下一个名字。例如,如果用户第一次输入数字2.然后他写了两个名字,然后要求再添加2个名字,程序应该保留前两个名字并准备存储在firstNames [2]。谢谢!

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

int main(void)
{
int amount;
//Asking user for number of records to input
printf("Please indicate the number of records you want to enter:");
scanf("%d", &amount);
printf("\n");

//Declaring dynamic array for first names
char **firstNames = (char**)malloc(amount * sizeof(char));
for (int i = 0; i < amount; i++)
{
    firstNames[i] = (char*)malloc(1 * sizeof(char));
}

//Prompting user for first name, last name, and scores
for (int count = 0; count < amount; count++)
{
    printf("Enter first name for user %d:", count + 1);
    scanf("%s", firstNames[count]);
}

int add;
printf("How many users do you want to add now:");
scanf("%d", &add);

int sum = amount + add;
firstNames = (char**)realloc(firstNames, sum * sizeof(char));


for (int count = amount; count < sum; count++)
{
    printf("Enter first name for user %d:", count + 1);
    scanf("%s", firstNames[count]);
}


return 0;
}

3 个答案:

答案 0 :(得分:2)

您有很多方面遇到麻烦。正如我原来的评论中所提到的,在担心重新分配之前,必须先正确分配内存。不是调用realloc并将回报分配给firstNames,而是创建临时指针以将realloc的回报分配给更好。如果realloc失败,则会返回NULL。这意味着所有现有数据都将丢失,因为您刚刚分配了firstNames = NULL。在将重新分配的空间分配给realloc之前,使用临时指针可以测试firstNames 是否成功

想到你的代码,还有其他几个方面可以改进。 始终初始化变量(零可以)。为什么?尝试从未初始化的变量中读取未定义的行为(错误)。您的输入例程至关重要。特别是使用scanf和阅读int/char数据。您必须确保在再次调用scanf之前清空输入缓冲区,否则它将使用newline(按[enter]生成)作为下一个值,导致程序跳过后面的scanf语句。您可以使用scanf使用newline来正确刷新输入缓冲区(stdin),并谨慎选择format string

当您获得输入时验证它! Knucklehead用户将输入任何内容。

初始化pointer to pointers时,通常最好使用calloc进行初始分配,而不是malloccalloc将所有值初始化为(零),从而阻止从未初始化的变量中读取。

关于程序流程,您需要最小化循环次数并消除不必要的代码块。如果没有其他原因,减少错误的机会。仔细思考你的循环。当您的所有操作都可以在一个中进行时,您使用了多个循环来计算相同的数字。这不是一个敲门声,这只是一个帮助您简化代码的建议。

当您要求在重新分配之前输入多少用户时,如果输入0会发生什么?你应该怎么处理?最好以您希望的方式检查和响应,而不是将其留给计算机认为可能未定义的内容。

这些是要点。我把这些想法纳入了一个例子。它总是可以改进,但我认为这将帮助您处理输入问题,并为您提供简化流程的示例。虽然没有必要,但我创建了几个函数来处理打印和释放内存。请记住,如果你分配内存,你有责任跟踪它并在完成后释放它。足够!这是一个例子。如果您有疑问,请告诉我。

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

void print_users (char **array, int sz);    /* funciton to print users  */
void free_memory (char **array, int sz);    /* function to free memory  */

int main (void)
{
    int amount = 0;     /* always intialize all variables */
    int i = 0;

    //Asking user for number of records to input
    printf("\nEnter the number of records to enter: ");
    scanf("%d%*c", &amount);                                    /* read int, discard newline            */
    printf("\n");

    if (!amount)                                                /* validate records to enter            */
    {
        fprintf (stderr, "\nerror: invalid input.\n\n");        /* if realloc fails, error and exit     */
        return 1;
    }

    //Declaring dynamic array for first names
    char **firstNames = calloc (amount, sizeof (*firstNames));  /* using your variable for sizeof (x)   */
    for (i = 0; i < amount; i++)                                /* prevents mistaken sizeof (wrong)     */
    {                                                           /* calloc initializes to NULL (zero)    */
        firstNames[i] = malloc (sizeof (**firstNames));         /* same for malloc                      */

        //Prompting user for first name, last name, and scores
        printf (" first name for user %d : ", i + 1);
        scanf ("%m[^\n]%*c", &firstNames[i]);                   /* read string and newline (discarded)  */
    }

    int add = 0;
    printf ("\nAny *additional* users to add: ");
    scanf ("%d%*c", &add);                                      /* read int, discard newline            */
    printf ("\n");

    if (!add)
    {
        print_users (firstNames, amount);
        free_memory (firstNames, amount);
        return 0;
    }

    int sum = amount + add;
    char **tmp = NULL;

    tmp = realloc (firstNames, sum * sizeof (*firstNames));     /* never realloc actual pointer to data */
                                                                /* if realloc fails pointer set to NULL */
    if (!tmp)               /* validate realloc succeeded   */
    {
        fprintf (stderr, "\nerror: reallocation failed.\n\n");  /* if realloc fails, error and exit     */
        return 1;
    }
    firstNames = tmp;       /* now assign to pointer        */

    for (i = amount; i < sum; i++)  /* why new var count, use i */
    {
        firstNames[i] = malloc (sizeof (**firstNames));         /* allocate new Names, prompt & store   */
        printf (" first name for user %d : ", i + 1);
        scanf ("%m[^\n]%*c", &firstNames[i]);
    }

    print_users (firstNames, sum);
    free_memory (firstNames, sum);

    return 0;
}

void print_users (char **array, int sz)
{
    printf ("\nUsers firstNames:\n\n");                 /* output users collecte in firstNames  */
    int i = 0;
    for (i = 0; i < sz; i++)
        printf ("  user[%d]  %s\n", i, array[i]);
}

void free_memory (char **array, int sz)
{
    int i = 0;
    for (i = 0; i < sz; i++)                           /* free allocated memory                */
        if (array[i])
            free (array[i]);
    if (array)
        free (array);
}

使用示例:

$ ./bin/reallocptr

Enter the number of records to enter: 2

 first name for user 1 : Jack
 first name for user 2 : Jill

Any *additional* users to add: 2

 first name for user 3 : Mike
 first name for user 4 : Moe

Users firstNames:

  user[0]  Jack
  user[1]  Jill
  user[2]  Mike
  user[3]  Moe

注意:请参阅下面的附录,否则4-bytes内存将在退出时保持未释放状态。


<强>附录

正如所指出的,只有一个char分配给每个firstName[i]指针,这些指针不足以分配完整的字符串。通常,实际上firstName[i]字符串分配可以使用strdupscanf等具有适当format string的函数自动处理。要使用scanf完全处理字符串,需要进行以下更改:

//Declaring dynamic array for first names
char **firstNames = calloc (amount, sizeof (*firstNames));  /* using your variable for sizeof (x)   */
for (i = 0; i < amount; i++)                                /* prevents mistaken sizeof (wrong)     */
{                                                           /* calloc initializes to NULL (zero)    */
    // firstNames[i] = malloc (sizeof (**firstNames));      /* let scanf auto-allocate              */

    //Prompting user for first name, last name, and scores
    printf (" first name for user %d : ", i + 1);
    scanf ("%m[^\n]%*c", &firstNames[i]);                   /* read string and newline (discarded)  */
}
...
for (i = amount; i < sum; i++)  /* why new var count, use i */
{
    // firstNames[i] = malloc (sizeof (**firstNames));      /* allocate new Names, prompt & store   */
    printf (" first name for user %d : ", i + 1);
    scanf ("%m[^\n]%*c", &firstNames[i]);
}

更改为free_memory()

void free_memory (char **array, int sz)
{
    int i = 0;
    for (i = 0; i < sz; i++)
        if (array[i])
            free (array[i]);
    if (array)
        free (array);
}

<强>输出/验证

Enter the number of records to enter: 2

 first name for user 1 : Jack
 first name for user 2 : Jill

Any *additional* users to add: 2

 first name for user 3 : Larry
 first name for user 4 : Moe

Users firstNames:

  user[0]  Jack
  user[1]  Jill
  user[2]  Larry
  user[3]  Moe

==13690==
==13690== HEAP SUMMARY:
==13690==     in use at exit: 0 bytes in 0 blocks
==13690==   total heap usage: 10 allocs, 10 frees, 468 bytes allocated
==13690==
==13690== All heap blocks were freed -- no leaks are possible

答案 1 :(得分:1)

char **firstNames = (char**)malloc(amount * sizeof(char));

这是一个双指针,需要为指向您信息的指针分配内存。

所以它应该是

char **firstNames = malloc(amount * sizeof(char *));/* No need to cast malloc() */

稍后你正在为这个内存做realloc(),你需要处理realloc()失败。所以使用临时指针来存储realloc()的返回值并分配地址回到firstNames

firstNames[i] = (char*)malloc(1 * sizeof(char));

你在每次迭代中分配一个字节,以便读取你需要更多内存的字符串。

答案 2 :(得分:1)

内存分配中的一些更正。

#define SIZE 10

char **firstNames = malloc(amount * sizeof(char *));
for (i = 0; i < amount; i++)
{
    firstNames[i] = malloc(SIZE * sizeof(char));
}

首先malloc为您要存储的条目分配内存 由于条目是指向另一个内存的指针,因此请使用malloc(amount * sizeof(char *))

第二个malloc只是为你要存储的实际字符串分配内存 其中SIZE是每个条目的字节数。


现在您想要添加更多用户,因此您使用realloc

int sum = amount + add;
firstNames = realloc(firstNames, sum * sizeof(char *));

/* Add the following to your code */
for (i = amount; i < sum; i++)
    firstNames[i] = malloc(SIZE * sizeof(char));

printf("Total Names: \n");
for ( i = 0; i < sum; i++)
    printf("%s\n", firstNames[i]);

这里第二个malloc用于为新添加的用户分配内存 它从(i = amount)开始,因为已经分配了amount内存。