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プラットフォームを使用している場合、へのポインタには4バイトかかりますchar。したがって、次のようになります。

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

つまり、16*BUFFERまたは16x50=800バイトをmallocしていることになります。これにより、50個の「fr」構造の配列を作成できます。

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

つまり、50の構造のメモリがありますが、それらの構造のコンテンツにはまだメモリがありません。構造体の各メンバーにメモリを割り当てる必要があります(そして、それらもすべて解放することを忘れないでください)。または、ポインタの代わりに配列を使用して静的メンバーにすることもできます。

2番目の問題:

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 に答える