4

因此,我正在尝试将 malloc 添加到我创建的电话簿应用程序中,但是由于我对 C 有点陌生,我不确定我所做的是否正确。我遇到了一个小问题,但我已经阅读了我拥有的初学者书籍,它并没有像我想要的那样详细,我无法通过搜索谷歌来判断我是否只是我设置 malloc 的方式完全错误,或者我错过了其他东西。

基本上我的结构中有 4 个数组,First_Name, Last_name, home, cell. 其中每一个都有 2 个功能,一个从用户那里获取信息的功能,一个打印用户信息并将其添加到电话簿的功能。我现在得到的是原始代码的一小部分,它只将名字添加到电话簿(所以它不是整个代码),并且在每个获取用户输入的函数中,我想添加 malloc 函数。现在我只设置了名字和第一个malloc,但我遇到的问题是当我去检查电话簿看名字是否输入成功时,程序退出了。如果我取出 malloc,它会成功运行。

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

#define BUFFER 50
    //Structure for contacts
typedef struct friends_contact {

    char *First_Name;
    char *Last_Name;
    char *home;
    char *cell;
} fr;

void menu(fr * friends, int *counter, int user_entry, int i);
void setFirst(fr *, int *, int i);
char getFirst(fr *, int i);
void add_contact(fr * friends, int *counter, int i);
void print_contact(fr * friends, int *counter, int i);

int main()
{

    int user_entry = 0;
    fr *friends;
    int counter = 0;
    int i = 0;
    menu(friends, &counter, user_entry, i);
    getch();
    return 0;
}

//Menu function
void menu(fr * friends, int *counter, int user_entry, int i)
{
    do {
        int result;

        printf("\nPhone Book Application\n");
        printf
            ("1) Add friend\n2) Delete friend\n3) Show a friend\n4)Showphonebook\n5)Exit\n");
        scanf("%d", &user_entry);

        if (user_entry == 1) {
            add_contact(friends, counter, i);
        }
        if (user_entry == 2) {

        }
        if (user_entry == 3) {

        }
        if (user_entry == 4) {
            print_contact(friends, counter, i);
        }
    } while (user_entry != 5);
}

void setFirst(fr * friends, int *counter, int i)
{
    // THE MALLOC FUNCTION!
    friends = (fr *) malloc(BUFFER * sizeof(fr));
    printf("Enter a first name \n");
    scanf("%s", friends[*counter].First_Name);
    if (friends != NULL) {

        free(friends);
    }
}

char getFirst(fr * friends, int pos)
{
    printf("%s ", friends[pos].First_Name);
    return *friends[pos].First_Name;
}

void add_contact(fr * friends, int *counter, int i)
{
    setFirst(friends, counter, i);
    (*counter)++;
}

void print_contact(fr * friends, int *counter, int i)
{
    for (i = 0; i < *counter; i++)
        if (strlen(friends[i].First_Name)) {
            getFirst(friends, i);
        }
}

希望给可以在这里帮助我的人打一个大大的绿色复选标记。

4

4 回答 4

8

您需要为整个记录分配内存,并为每个字段单独分配内存。例如:

void string_realloc_and_copy (char **dest, const char *src)
{
  size_t len = strlen (src);
  *dest = realloc (*dest, len + 1);
  memcpy (*dest, src, len + 1);
}

typedef struct
{
  char *name;
  char *title;
} record;

record * record_new ()
{
  record *r = malloc (sizeof (record));
  r->name = NULL;
  r->title = NULL;
  return r;
}

void record_free (record *r)
{
  free (r->name);
  free (r->title);
  free (r);
}

void record_set_name (record *r, const char *name)
{
  string_realloc_and_copy (&r->name, name);
}

void record_set_title (record *r, const char *title)
{
  string_realloc_and_copy (&r->title, title);
}

现在创建一条记录并用从用户读取的值填充它:

record *r;
char buffer[100 + 1];

r = record_new ();

printf("Enter a first name \n");
if (scanf ("%100s", buffer) == 1) {
  record_set_name (r, buffer);
}

...
于 2012-11-09T17:52:40.640 回答
1

这里遇到了一些问题:

void setFirst(fr*friends, int* counter, int i) {
   // THE MALLOC FUNCTION!
   friends=(fr*) malloc(BUFFER*sizeof(fr));  <-- This is not doing what you're thinking

sizeof(fr)将是 4 个字符指针所需的大小。例如,如果您在 32 位 x86 平台上,则指向 a 的指针需要 4 个字节char,因此:

sizeof(fr) == 4 x 4 == 16 bytes

所以现在你正在 malloc'ing 16*BUFFER 或 16x50 = 800 字节。这允许您拥有一个包含 50 个“fr”结构的数组。

fr * friend
        |
        +--------> FirstName*
            |      LastName*
            |      home*
            |      cell*
            +----> FirstName*
            |       LastName*
            |      home*
            |      cell*
            ...

所以你有 50 个结构的内存,但是这些结构的内容仍然没有内存。您需要为结构的每个成员分配内存(并且不要忘记释放所有这些成员),或者您可以使用数组而不是指针使它们成为静态成员。

第二个问题:

if(friends != NULL)  <-- if malloc was successful
{
     free(friends);  <-- release the memory

你刚刚失去了所有的朋友。:)
您确实需要释放内存,但在程序结束时或在您使用它的位置结束时。如果您分配然后立即释放,那么内存就消失了,您将无法再访问它。

于 2012-11-09T17:50:09.210 回答
0

您的结构仅包含指针,而不是分配的内存。您最好将其定义为保存您写入名称等的数组:

typedef struct friends_contact{

    char First_Name[20];
    char Last_Name[20];
    char home[20];
    char cell[20];
} fr;

在这里,我将每个字段设置为 20 个字符长,但您可以更改以适合。


编辑:是的,当然你可以使用动态内存,但值得费心吗?动态字符串的优点是它们的大小可以完全正确;您可能会节省几个字节,并保证能够将名称放入字段中。但是是否有许多名称超过 20 个字符,是否必须缩写一些?使用 malloc,当然有很多繁琐的分配(每个都可能失败)和释放。

作为一种折衷方案,可以使电话号码固定大小(它们不会改变)并且名称是动态的;strdup然后使用(也可能失败)分配名称。

typedef struct friends_contact{

    char *First_Name;
    char *Last_Name;
    char home[12];
    char cell[12];
} fr;
于 2012-11-09T17:38:20.003 回答
0

这里还有几件事需要考虑,但首先考虑以下内容。

setFirst中,您正在free输入friends缓冲区,本质上是在说“我不再需要这个”。当你这样做时,那个记忆就会消失。如果您要为调用者动态分配结构,您要么必须提供单独的释放函数,要么让您的用户知道清理该结构是他们的责任。

此外,您只需要更改朋友指针的本地副本。如果要将调用者的指针指向新缓冲区,则需要将参数类型更改为fr**.

于 2012-11-09T17:50:25.243 回答