【问题标题】:Strange output while using dynamic memory allocation i C使用动态内存分配时的奇怪输出 i C
【发布时间】:2015-06-03 15:19:08
【问题描述】:

我正在编写此代码,但尚未完成。但是在测试添加新联系人功能和打印功能时,我得到了这个奇怪的输出。只要我不添加多个联系人,一切看起来都不错。我在这里做错了什么?

//Libraries:
#include <stdio.h>
#include <stdlib.h>

//Function prototypes
int showMenu(); //Shows user options

//Main function
int main() {

    //Variable declerations
    int i = 0;
    int iOption = 0;
    int iContacts = 0;
    char *cPhoneBook_name;
    int *iPhoneBook_nr;

    cPhoneBook_name = (char *) calloc(1, 80 * sizeof(char));
    iPhoneBook_nr = (int *) calloc(1, sizeof(int));

    do {

        //Memory check
        if(cPhoneBook_name == NULL || iPhoneBook_nr == NULL){
            printf("\nOut of Memory!\n");
            return;
        }

        //Show menu
        iOption = showMenu();

        switch (iOption) {
            case 1: //Add contact
                printf("\nEnter name:\n");
                scanf("%s", &cPhoneBook_name[iContacts]);
                printf("\nEnter number:\n");
                scanf("%d", &iPhoneBook_nr[iContacts]);
                cPhoneBook_name = realloc(cPhoneBook_name, 80 * sizeof(char));
                iPhoneBook_nr = realloc(iPhoneBook_nr, sizeof(int));
                iContacts += 1;
                break;
            case 2: //Modify contact
                //Code here
                break;
            case 3: //Show contacts
                for(i = 0 ; i < iContacts ; i++) {
                    printf("\n%s %d\n", &cPhoneBook_name[i], iPhoneBook_nr[i]);
                }
                break;
            case 4: //Free memory (delete contacts)
                free(cPhoneBook_name);
                free(iPhoneBook_nr);
                break;
        }
    }while(iOption != 5);//Exit if iOption is 5;

    system("clear");
    return 0;
}


//Function definition - showMenu()
int showMenu() {

    int iOption = 0;

    //system("clear");

    printf("\n   Phone book   \n");
    printf("------------------------\n");
    printf("1. Add new contact.\n");
    printf("2. Edit existing contact\n");
    printf("3. Show contact(s)\n");
    printf("4. Clear phone book\n");
    printf("5. Exit\n");
    printf("------------------------\n");
    printf("Option --> ");
    scanf("%d", &iOption);

    return iOption;
}
//---------------------------------------------------------

【问题讨论】:

  • 给我们看一个这个“奇怪的输出”的例子,否则我们只是在猜测。
  • 你为什么分配内存而不往里面放任何东西?
  • 你也应该在程序退出前进行释放。
  • 您的主要问题是您的 scanf 正在进入未分配的内存。

标签: c


【解决方案1】:

问题在于:

printf("\n%s %d\n", &cPhoneBook_name[i], iPhoneBook_nr[i]);

cPhoneBook_name 如果是 char[] 类型。例如,表达式char[1] 为您提供列表中的第二个字符。虽然代码中的名称是 80 chars 宽。所以试试:

printf("\n%s %d\n", &cPhoneBook_name[i*80], iPhoneBook_nr[i]);

编辑:

我也发现了这个:

cPhoneBook_name = realloc(cPhoneBook_name, 80 * sizeof(char));

没有效果,因为您正在将 cPhoneBook_name 的大小从 80 调整为 80。 试试:

    cPhoneBook_name = realloc(cPhoneBook_name, (iContacts+1) 80 * sizeof(char)); 

还有: scanf("%s", &cPhoneBook_name[80*iContacts]);

【讨论】:

  • 这一行也没有效果。 iPhoneBook_nr = realloc(iPhoneBook_nr, sizeof(int)); 并未能扩展数字数组。
  • 很好的发现:)。所以一般只记得pointer = realloc(pointer*newItemCount*sizeof(type))
  • 咳咳,pointer = realloc(pointer , newItemCount*sizeof(type)).
  • 哈哈,哎呀,我去煮咖啡;)
  • 谢谢@Davidvanrijn!它帮助很大!我在您的帮助下完成了代码。 :-)
【解决方案2】:

当您输入多个联系人时,这很可能是您“奇怪输出”的根源:

cPhoneBook_name = realloc(cPhoneBook_name, 80 * sizeof(char));

您实际上并没有扩展cPhoneBook_name 数组的大小;在realloc 调用中,第二个参数是数组的新大小,而不是添加到现有大小的数量。

话虽如此,这整个方法都是错误的;您没有创建字符串数组,而是(未成功)创建了一个字符串,每次添加联系人时都会扩展该字符串,并且您的 iContacts 索引将指向 i'th 字符 的字符串,而不是字符串列表中的 i'th 字符串。

这是一种应该可行的方法:

#define ROWS 5 // start with 5 rows in your contact list

// Create a type to store a single phone book entry
struct PhoneBookEntry {
  char name[80];  // fixed size to keep things simple
  int number;
};

// Create an array that can initially store ROWS
// phone book entries
struct PhoneBookEntry *phoneBook = malloc ( sizeof *phoneBook * ROWS );
size_t phoneBookRows = ROWS;
...
case 1: // Add contact
  // Before adding a contact, see if we need to extend the phone book
  // array
  if ( iContacts == phoneBookRows )
  {
    // double the size of the phone book array
    struct PhoneBookEntry *tmp = realloc( phoneBook, 2 * sizeof *phoneBook * phoneBookRows );
    if ( tmp )
    {
      phoneBook = tmp;
      phoneBookRows *= 2; 
    }
    else
    {
      fprintf( stderr, "Could not extend phone book!\n" );
      break;
    }
  }
  ...
  scanf( "%s", phoneBook[iContacts].name ); // note no & operator; arrays are special
  ...
  scanf( "%d", &phoneBook[iContacts].number );

注意事项:

首先,不要在 C 代码中转换 malloccallocrealloc 的结果;这是不必要的,并且在 C89 下编译器可以掩盖错误。您确实需要在 C++ 代码中转换这些函数的结果,但如果您正在编写 C++,则无论如何都不应该使用 malloccallocrealloc

其次,避免使用类型名称作为sizeof 参数,这样可以提供帮助。请改用以下内容:

T *p = malloc( N * sizeof *p );

表达式*p的类型是T,所以sizeof *p等价于sizeof (T)。这样,malloc 将始终分配正确的内存量,而不管T,如果您决定更改T,您只需在一个地方进行更改。

第三,realloc如果不能满足请求,会返回NULL;如果您将 NULL 分配给您的 phoneBook 变量,您将失去对已分配内存的引用。将realloc 的结果分配给临时变量,测试NULL,然后将其分配给您的phoneBook 变量会更安全。

第四,realloc 调用可能很昂贵,因此您希望在合理的情况下尽量减少它们。将数组的大小加倍是一种常用技术。

【讨论】:

    猜你喜欢
    • 2021-05-19
    • 2012-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多