简体   繁体   English

在c中使用malloc和结构

[英]Using malloc with structures in c

So I'm trying add malloc to a phonebook application that I created, but since I'm kind of new to C I'm not sure if what I'm doing is correct. 所以我正在尝试将malloc添加到我创建的电话簿应用程序中,但由于我是C的新手,我不确定我所做的是否正确。 I've run into a small problem, but I've read through the beginner book that I have, and it doesn't go though as much detail as I would like, I can't tell by searching Google if I'm just completely wrong in how I set up the malloc or if there is something else I missed. 我遇到了一个小问题,但是我已经阅读了我所拥有的初学者书籍,但它并没有像我想的那样详细,我无法通过搜索Google来判断我是否只是我如何设置malloc完全错误,或者我错过了什么。

Basically what I've got are 4 arrays in my structure, First_Name , Last_name , home , cell . 基本上我得到的是我的结构中的4个数组, First_NameLast_namehomecell Each one of these have 2 functions, a function that gets the info from the user and a function that prints and adds the user info to the phonebook. 其中每个都有2个功能,一个从用户获取信息的功能和一个打印并将用户信息添加到电话簿的功能。 What I've got right now is a small snipit of the original code that only adds the first name to the phonebook(so it's not the entire code) and in each function that gets the user input, I want to add the malloc function. 我现在所拥有的是原始代码的一小部分,它只将第一个名称添加到电话簿中(因此它不是整个代码),并且在每个获取用户输入的函数中,我想添加malloc函数。 Right now I've only got the first name and the first malloc set up, but the issue I have is that when I go to check the phonebook to see if the name was entered successfully, the program quits. 现在我只有第一个名字和第一个malloc设置,但问题是,当我去检查电话簿以查看名称是否输入成功时,程序退出。 If I take out the malloc, it works successfully. 如果我取出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);
        }
}

Looking to give a big green check mark to whoever can help me out here. 希望能给那些可以帮助我的人一个大的绿色复选标记。

You need to allocate memory both for the record as a whole and separately for each field. 您需要为整个记录分配内存,并为每个字段分别分配内存。 For example: 例如:

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);
}

Now to create a record and fill it with values read from the user: 现在创建一个记录并用从用户读取的值填充它:

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);
}

...

Got some problems here: 这里遇到了一些问题:

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) is going to be the size required for 4 pointers to character. sizeof(fr)将是4个指向character的指针所需的大小。 For example if you're on a 32-bit x86 platform it takes 4 bytes for a pointer to a char , thus: 例如,如果您使用的是32位x86平台,则指向char的指针需要4个字节,因此:

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

So now you're malloc'ing 16*BUFFER or 16x50 = 800 bytes. 所以现在你正在使用16 * BUFFER或16x50 = 800字节。 This allows you to have an array of 50 'fr' structures. 这允许您拥有50个'fr'结构的数组。

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

So you've got the memory for 50 structures, but the contents of those structures still don't have memory. 所以你有50个结构的内存,但这些结构的内容仍然没有内存。 You need to assign memory to each member of the structure (and don't forget to free all those as well), or you could make them static members with arrays instead of pointers. 您需要为结构的每个成员分配内存(并且不要忘记释放所有这些成员),或者您可以使用数组而不是指针使它们成为静态成员。

Second problem: 第二个问题:

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

You just lost all your friends. 你刚失去了所有的朋友。 :) :)
You do need to free the memory but at the end of the program or at the end of where you're using it. 你需要释放内存,但是在程序结束时或在你使用它的地方结束时。 If you assign and then free right away, then the memory is gone and you can't access it anymore. 如果您分配然后立即释放,那么内存已经消失,您将无法再访问它。

Your structure contains just pointers, not allocated memory. 您的结构只包含指针,而不是分配内存。 You would be better defining it to hold arrays into which you write names etc: 你最好定义它来保存你写名字的数组等:

typedef struct friends_contact{

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

Here I have made each field 20 characters long, but you can change that to suit. 在这里,我已经使每个字段长20个字符,但你可以改变它以适应。


Edit: yes of course you can use dynamic memory, but is it worth the bother? 编辑:是的,你当然可以使用动态内存,但值得打扰吗? The advantage of dynamic strings is that they can be exactly the right size; 动态字符串的优点是它们可以是完全正确的大小; you might save a few bytes and you guarantee being able to fit the names into the fields. 您可以保存几个字节,并保证能够将名称放入字段中。 But are there many names longer than 20 chars and would it matter to have to abbreviate a few? 但是有多个名字超过20个字符,是否必须缩写几个? With malloc, there is a lot of fiddly allocation (each of which can fail) and freeing too, of course. 对于malloc,当然有很多繁琐的分配(每个都可能失败)和释放。

As a compromise one might make the phone numbers fixed size (they don't change) and the names dynamic; 作为妥协,可以使电话号码固定大小(它们不会改变)和名称动态; then allocate the names using strdup (which can also fail). 然后使用strdup (也可能失败)分配名称。

typedef struct friends_contact{

    char *First_Name;
    char *Last_Name;
    char home[12];
    char cell[12];
} fr;

There are several more things to consider here, but for a start consider the following. 这里还有几件事要考虑,但首先要考虑以下几点。

In setFirst , you're free ing your friends buffer, in essence saying "I don't need this anymore." setFirst ,你可以free你的friends缓冲区,本质上说“我不再需要它了”。 When you do this, that memory just goes away. 当你这样做时,那个记忆就会消失。 If you're going to dynamically allocate structures for the caller, you either have to provide a separate deallocation function, or let your user know it's their responsibility to clean up that structure. 如果您要为调用者动态分配结构,则必须提供单独的释放功能,或者让您的用户知道清理该结构是他们的责任。

Also, you're only ever changing the local copy of the friends pointer. 此外,您只需要更改好友指针的本地副本。 If you want to point the caller's pointer to a new buffer, you need to change the argument type to fr** . 如果要将调用者的指针指向新缓冲区,则需要将参数类型更改为fr**

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM