【问题标题】:Segmentation fault after entering in a string from struct从结构输入字符串后出现分段错误
【发布时间】:2018-10-18 20:51:52
【问题描述】:

所以正如问题所说,每次我尝试为客户输入名称时都会遇到分段错误。该程序确实会编译并运行,直到它到达客户名称部分。我不确定问题是否与malloc有关。谁能告诉我我做错了什么?我一直试图弄清楚这一点,但没有运气。谢谢

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

#define END_OF_STRINGS  '\0' 
#define NEWLINE         '\n'    
#define MAX_CUSTOMERS   100     
#define MIN_CUSTOMERS   2     
#define MAX_NAME_LENGTH 20    
#define DB_ALLOC_ERR    1  
#define QUIT            0  

struct customer
{
    char  *p_last_name[MAX_NAME_LENGTH + 1];
    float amount_owed;
    int   priority;
};

void print_instructions();
int  number_of_customers();
void get_accounts(struct customer *p_customer_start, int
    customer_amount);
void clean_names(struct customer *p_customer_start, int
    customer_amount);
void sort_names(struct customer *p_customer_start, int
    customer_amount);
void print_results(struct customer *p_customer_start, int
    customer_amount);

int main()
{
    struct customer *p_customer;
    int    customer_amount;


    while (print_instructions(), (customer_amount =
        number_of_customers()) != QUIT)
    {
        if ((p_customer = (struct customer *)malloc(sizeof(*p_customer) *
            MAX_NAME_LENGTH)) == NULL)
        {
            printf("\nError #%d occurred in main()", DB_ALLOC_ERR);
            printf("\nCannot allocate memory for database of customer ");
            printf("\naccountable records");
            printf("\nThe program is aborting");
            exit  (DB_ALLOC_ERR);
        }

        get_accounts (p_customer, customer_amount);
        clean_names  (p_customer, customer_amount);
        sort_names   (p_customer, customer_amount);
        print_results(p_customer, customer_amount);

        printf("%c", NEWLINE);

        free(p_customer);
    }

    return 0;
}

void print_instructions()
{
    printf("\n\nThis program allows you to input customers which owe");
    printf("\nyou money (your accounts receivable), and manage these");
    printf("\naccounts in a database.  You will enter the following:");
    printf("\n   Customer last name (1-20 characters)");
    printf("\n   Amount the customer owes (to the exact cent)");
    printf("\n   Customer priority (1=VIP, 2=Important, 3=Regular)");
    printf("\nFrom 2 to 100 customers may be processed.");
    return;
}

int number_of_customers()
{
    int user_choice;

    printf("\n\nGet the customers for the database");
    printf("\n--------------------------------------------------");

    do
    {
        printf("\nHow many customers do you have (%d to %d, %d=quit): ", MIN_CUSTOMERS, MAX_CUSTOMERS, QUIT);
            scanf ("%d", &user_choice);
    } while ((user_choice < MIN_CUSTOMERS ||
        user_choice > MAX_CUSTOMERS) && user_choice != QUIT);
    return user_choice;
}

void get_accounts(struct customer *p_customer_start, int
    customer_amount)
{
    struct customer *p_customer;

    for (p_customer = p_customer_start; (p_customer - p_customer_start)
        < customer_amount; p_customer++)
    {
        printf("\nCustomer number %d", (int)(p_customer -
            p_customer_start + 1));
        printf("\n   Enter the customer's last name: ");
        scanf ("%20s", p_customer->p_last_name[MAX_NAME_LENGTH + 1]);
        getchar();
        do
        {
            *p_customer->p_last_name[MAX_NAME_LENGTH] = getchar();
            p_customer->p_last_name[MAX_NAME_LENGTH]++;
        } while (!NEWLINE);
        p_customer->p_last_name[MAX_NAME_LENGTH + 1] = END_OF_STRINGS;
        printf("\n  Enter the amount owed: ");
        scanf ("%f", &p_customer->amount_owed);
        do
        {
            printf("\n  Enter the customer's priority (1-3): ");
            scanf ("%d", &p_customer->priority);
        } while (p_customer->priority < 1 || p_customer->priority > 3);
    }
    return;
}

void clean_names(struct customer *p_customer_start, int
    customer_amount)
{
    char   *p_fast = p_customer_start->p_last_name[MAX_NAME_LENGTH],
        *p_slow = p_customer_start->p_last_name[MAX_NAME_LENGTH];

    if (tolower(*p_fast))
        *p_slow++ = toupper(*p_fast);
    while (*p_fast != END_OF_STRINGS)
    {
        if (!isspace(*p_fast) || isalpha(*p_fast))
            *p_slow++ = tolower(*p_fast);
        p_fast++;
    }
    *p_slow = END_OF_STRINGS;
    return;
}

void sort_names(struct customer *p_customer_start, int
    customer_amount)
{
    char   *p_inner[MAX_NAME_LENGTH],
        *p_outer[MAX_NAME_LENGTH],
        temp[MAX_NAME_LENGTH];

    for (p_outer[MAX_NAME_LENGTH] = p_customer_start ->
        p_last_name[MAX_NAME_LENGTH]; (p_outer - p_customer_start ->
            p_last_name)
        < customer_amount; p_outer[MAX_NAME_LENGTH]++)
    {
        for (p_inner[MAX_NAME_LENGTH] = p_outer[MAX_NAME_LENGTH + 1];
            (p_inner - p_customer_start ->
                p_last_name) < customer_amount; p_inner[MAX_NAME_LENGTH]++)
        {
            if (strcmp(p_outer[MAX_NAME_LENGTH],
                p_inner[MAX_NAME_LENGTH]))
            {
                temp[MAX_NAME_LENGTH] = *p_outer[MAX_NAME_LENGTH];
                *p_outer[MAX_NAME_LENGTH] = *p_inner[MAX_NAME_LENGTH];
                *p_inner[MAX_NAME_LENGTH] = temp[MAX_NAME_LENGTH];
            }
        }
    }
    return;
}

void print_results(struct customer *p_customer_start, int
    customer_amount)
{
    char   last_name[MAX_NAME_LENGTH];
    float  amount_owed = p_customer_start->amount_owed;

    printf("\n  Here is the accounts receivable customer database");
    printf("\n=====================================================");
    printf("\n   Customer Name         Amount        Priority");
    printf("\n--------------------    ---------    -------------");
    printf("\n          %s         $    %.2f   ", last_name,
        amount_owed);

    switch (p_customer_start->priority)
    {
    case 1:
        printf("1 (VIP)");
        break;

    case 2:
        printf("2 (Important)");
        break;

    case 3:
        printf("3 (Regular)");
        break;
    }
    printf("\n\n******* End Of Customer Database Processing *******");
    return;
}

【问题讨论】:

  • 通过 valgrind 运行您的代码。如果你对内存管理不善,它会告诉你在哪里。确保使用调试符号进行编译(gcc:-g 选项)。
  • Remove * from char *p_last_name[MAX_NAME_LENGTH + 1]; 你声明的指针数组。
  • 谁能告诉我我做错了什么?您没有使用调试器来缩小问题范围,以便您可以提出我们可以回答的问题。跨度>
  • @PaulDann,名字的主要问题是char *p_last_name[MAX_NAME_LENGTH + 1];。这将 p_last_name 声明为 指针数组(带有 21 个指针)而不是 字符数组(带有21 个字符)。正确使用malloc 并没有什么魔力。它分配一块大小为您所用的内存块。 必须将该块的起始地址分配给您将用于访问内存的指针。然后,您必须将您希望存储在那里的任何信息复制到起始地址。 p_customer 分配给20 客户。从那里去。
  • 我这样说并不是不屑一顾。为了在您的程序上下文中“向您展示如何使malloc 工作”,我基本上最终会重新编写您的程序。从教育的角度来看,这对您几乎没有帮助。更好地学习How to debug small programs 并与鸭子交谈...真的,它有帮助:) 在此期间,请访问Do I cast the result of malloc?。隔离malloc 有问题的地方(在代码中添加printf ("in function() at line x\n");

标签: c segmentation-fault malloc


【解决方案1】:

我相信你的问题的开始就在这里:

struct customer
{
    char  *p_last_name[MAX_NAME_LENGTH + 1];
    float amount_owed;
    int   priority;
};

使用该代码创建 21 个 指针 指向 char。

你想要的是指向空间的字符指针,它将保存MAX_NAME_LENGTH + 1 个字符

因此你会想要一些简单的东西:

struct customer
{
   char  last_name[MAX_NAME_LENGTH + 1];
   float amount_owed;
   int   priority;
};

我也将 p_last_name 更改为 last_name,这样看起来它看起来更合乎逻辑,但你可以随意称呼它,但是说 p_last_name 是在暗示它是一个不需要的指针,而且它读起来很糟糕

在声明或定义变量时,从右到左阅读, 然后它将是一个数组,因为 [] 是 21 大,称为 last name,它是一个 char 数据类型的数组。

现在 C 的问题是数组和指针有一些共同点,或者经常会混淆......因为它们在技术上是相同的。您定义的任何数组,反过来又在内存中分配空间,只不过是指向数组开头的指针,就是这样!

当您执行last_name[7] 之类的操作时,7 是数组开头的 跳转 次数,在您的情况下始终称为 last_name。跳转的大小完全取决于定义数组时的数据类型。在您的情况下,它是 char,它是 1 个字节,因此 last_name[7] 的跳转将距离 last_name 指向的位置 7 个字节。

For example if the contents in memory where `last_name` points to is    abcdefghijklmnopqrst
  • 然后char last_name[MAX_NAME_LENGTH + 1]; 将定义一个名为last_name 的变量,从技术上讲,它是一个字符指针,指向MAX_NAME_LENGTH + 1 字节的连续内存块因为数据类型为char,它是一个指向开头的指针那块内存。
  • *last_namelast_name[0] 相同 deferences 字符指针 last_name 以便它返回内存的内容 a
  • *(last_name+2)last_name[2] 相同,即 c

另外,在

int main()
{
   struct customer *p_customer;
   int    customer_amount;

这条语句struct customer *p_customer; 创建了一个名为 p_customer一个 指针,该指针将指向某个内存块(尚未发生),它属于上面定义的数据类型struct customer。好的到那里。然后在

if ((p_customer = (struct customer *)malloc(sizeof(*p_customer) * MAX_NAME_LENGTH)) == NULL)

你使用malloc为你正在做的事情保留一些内存,你真的在​​做sizeof( a pointer )

除了在struct customer 中正确定义一个名为last_name 的21 字节字符数组之外,您还应该做的是(struct customer *) malloc( sizeof( struct customer ))

它应该用英语逻辑地读出,通常是从右到左,如果它不怀疑有问题。另外,编译时学会使用-W,它可以成为你的朋友,提醒你注意这样的问题。

您的原始代码可能没有为您在p_last_name 中输入的字符数分配或保留足够大的内存。

【讨论】:

  • 不要忘记 print_results() 通过尝试将未初始化的 char last_name; 打印为指针 %s 来调用 Undefined Behavior,以及验证返回的完全失败scanf(或处理 EOF,或 inputmatching 失败)并告诫不要在取消引用成员时在 " -&gt; " 周围添加空格。
  • 好吧,我明白我做错了什么。非常感谢你们的帮助!
  • 太棒了——这就是进步:p
  • @PaulDann,我很遗憾,您可能会发现 The Following 有用。
  • 非常感谢!非常感谢大家抽出时间来帮助我
猜你喜欢
  • 2015-01-18
  • 2020-06-24
  • 1970-01-01
  • 2017-08-01
  • 2015-02-15
  • 1970-01-01
  • 1970-01-01
  • 2012-06-22
  • 1970-01-01
相关资源
最近更新 更多