【问题标题】:C structs and linked lists struggleC 结构和链表的斗争
【发布时间】:2017-06-28 23:09:27
【问题描述】:

所以,我们刚开始在我的在线课程中学习链表和数据结构,但我一直在为这个主题而苦苦挣扎。我对指针有一个大致的了解,但是当你把所有东西结合起来时,我就完全迷失了。

所以对于这个程序,我应该处理员工数据并通过使用结构和指针来访问它。但是,我认为我没有将正确的值传递给函数,因为数据没有被保存并且我无法访问它。任何帮助将不胜感激。

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

struct address {
    char street[49];
    char city[29];
    char state[2];
    char zip[5];
};

struct data{
    char name[39];
    struct address addy;
    float salary;
    struct data *next;
} emp;

void LIST(struct data* head);
void INSERT(struct data* head, char* name, struct address addr, float salary);
void DELETE(char* name, struct data* head);
void EDIT(struct data* head, char* name, struct address addr, float salary);
void CALCPAYROLL(struct data* head);
void HELP();

int main()
{
    char input[15];
    int quitter = 1;
    struct data *head = NULL;
    head = malloc(sizeof(emp));
    if (head == NULL){
        return 1;
    }

    while(quitter == 1)
    {
        printf(" enter command:  \n");
        fgets(input,15, stdin);
        input[strlen(input) -1] = '\0';
        if((strcmp(input, "List") == 0) || (strcmp(input, "list") == 0))
        {
            LIST(head);
        }
        if((strcmp(input, "Insert") == 0) || (strcmp(input, "insert") == 0))
        {
            scanf("%s-%s-%s-%s-%s-%f", head->name, head->addy.street, head->addy.city, head->addy.state, head->addy.zip, &head->salary);
            INSERT(head, head->name, head->addy, head->salary);
        }
        if ((strcmp(input, "Delete") == 0) || (strcmp(input, "delete") == 0))
        {
            DELETE(head->name, head);
        }
        if ((strcmp(input, "Edit") == 0) || (strcmp(input, "edit") == 0))
        {
            EDIT(head, head->name, head->addy, head->salary);
        }
        if ((strcmp(input, "Payroll") == 0) || (strcmp(input, "payroll") == 0))
        {
            CALCPAYROLL(head);
        }
        if ((strcmp(input, "Help") == 0) || (strcmp(input, "help") == 0))
        {
            HELP();
        }
        if ((strcmp(input, "Quit") == 0) || (strcmp(input, "quit") == 0))
        {
            printf("============\nGood bye!\n");
            quitter = 0;
        }
    }
    return 0;
}

void LIST(struct data* head)
{
    struct data* temp = head;
    while (temp) {
        printf("%s\n%s\n%s, %2s %5s\n%9.2f\n-----\n", temp->name, temp->addy.street, temp->addy.city, temp->addy.state, temp->addy.zip, temp->salary);
        temp = temp->next;
        printf("%s\n%s\n%s, %2s %5s\n%9.2f\n-----\n", temp->name, temp->addy.street, temp->addy.city, temp->addy.state, temp->addy.zip, temp->salary);
        temp = temp->next;
    }
}

void INSERT(struct data* head, char* name, struct address addr, float salary)
{
    struct data* newEmployee = NULL;
    newEmployee = (struct data*)malloc(sizeof(emp));

    strcpy(newEmployee->name, head->name);
    newEmployee->salary = head->salary;

    strcpy(newEmployee->addy.street, head->addy.street);

    strcpy(newEmployee->addy.city, head->addy.city);

    strcpy(newEmployee->addy.state, head->addy.state);

    strcpy(newEmployee->addy.zip, head->addy.zip);
    struct data* temp = head;
    while(temp->next && temp->next->name > newEmployee->name) 
    {
        temp = temp->next;
    }
    newEmployee->next = temp->next;
    temp->next = newEmployee;

}

void DELETE(char* name, struct data* head)
{
    char del[39];
    scanf("%39s", del);
    struct data * toBeDeleted = NULL;
    struct data * temp = head;
    while (strcmp(del, temp->name) == 0) 
        {
           strcpy(temp->next->name, temp->name);

           temp->addy = temp->next->addy;
           temp->salary = temp->next->salary;
           toBeDeleted = temp->next;
           temp->next = temp->next->next;
           free(toBeDeleted);
           printf("RECORD DELETED\n");
        }
        temp = temp->next;
        printf("RECORD NOT FOUND\n");
}

void EDIT(struct data* head, char* name, struct address addr, float salary)
{
    char edit[39];
    scanf("%39s", edit);
    struct data* temp = head;
    while (strcmp(edit, temp->name) == 0) 
        {
            temp->addy = addr;
            temp->salary = salary;

            printf("RECORD EDITED\n");
            return;
        }
        temp = temp->next;
    printf("RECORD NOT FOUND\n");
}

void CALCPAYROLL(struct data* head)
{
    struct data* temp = head;
    float total;
    while (temp) 
    {
        total += temp->salary;
        temp = temp->next;
    }
    printf("total payroll: %f", total);
}

void HELP()
{
    printf("commands:\n");
    printf("List - shows the list of employees\n");
    printf("Insert - Creates a new employee record\n");
    printf("Delete - Deletes an existing employee record\n");
    printf("Edit - Modifies the contents of an employee record\n");
    printf("Payroll - Calculates and displays the total payroll\n");
    printf("Help - Displays the set of available commands\n");
    printf("Quit - Prints the message ""good bye!"" and exits the program" );
}

【问题讨论】:

  • 次要问题:在您的 INSERT 函数中,您尝试使用 &gt; 运算符比较两个字符串。可能你想要strcmp(name1, name2) 之类的东西,结果的符号确定哪个是字母顺序。
  • 对函数名使用全部大写字母会使代码更难理解。所有大写字母(按照惯例)仅用于宏名称、常量名称。在 C 中,这意味着 #define ALL_CAPS_NAME 1 是预期的,但不是函数名称。对于函数名称,建议使用 lowerCamelCase()snake_name()
  • 发布的代码包含几个“神奇”数字。 “魔术”数字是没有依据的数字。 IE。 2、5、15、29、39、49。“神奇”数字使代码更难理解、调试等。建议使用enum 语句或#define 语句为这些“神奇”数字赋予有意义的名称,然后在整个代码中使用这些有意义的名称。
  • 一般来说,最好在执行==比较时将文字放在左侧,然后编译器会捕获一些像使用=而不是==这样的按键错误,而不是比你白发苍苍,而且在调试问题时遇到很多挫折
  • 应检查调用 fgets() 的返回值以确保操作成功

标签: c data-structures struct linked-list


【解决方案1】:

首先,我要赞扬你的演讲非常简洁。代码可读且易于理解。我发现它的唯一错误是所有大写名称通常保留给使用#define 声明的宏和常量。

这里:

struct data{
    char name[39];
    struct address addy;
    float salary;
    struct data *next;
} emp;                  // declaring a variable at the same time as the structure? Not very nice.

我发现当您创建第一个列表项 head 时会发生一个问题。 Insert 必须有办法修改head 参数。这需要额外的间接级别。 INSERT 还应该返回一个错误代码,以防 malloc 失败,执行此操作的常用方法是在错误时返回负值 (-1)。

void INSERT(struct data* head, char* name, struct address addr, float salary)

// should be 
int INSERT(struct data** head, char* name, struct address addr, float salary)

head 在入口时为NULL 时,您必须稍微更改逻辑以使用新分配的缓冲区设置head。然后调用 INSERT 就变成了。

   if (INSERT(&head, name, &addr, salary) < 0)
   {
      // error !
   }

我发现 INSERT 中的数据分配存在问题。

struct data* newEmployee = NULL;
//newEmployee = (struct data*)malloc(sizeof(emp)); // ?? you allocate a struct data, what's emp?
// should read
newEmployee = (struct data*)malloc(sizeof(struct data)); 

DELETE 和 EDIT 不起作用。他们找不到书面的雇员。您应该考虑使用 find() 函数,如下所示:

data* FindEmployeeData(data* head, const char* name)
{
   while (head)
   {
      if (strcmp(head->name, name) == 0)
        break;
      head = head->next;
   }
   return head;
}

在为员工编写新操作时,这可以节省时间。

在插入中:

while(temp->next && temp->next->name > newEmployee->name) 

我认为应该将字符串与 strcmp() 进行比较...

在DELETE中:与INSERT相同,该函数可以改变列表的头部

int DELETE(data** head, const char* name); // returns -1 on error.

这里:

scanf("%s-%s-%s-%s-%s-%f", head->name, head->addy.street, head->addy.city, head->addy.state, head->addy.zip, &head->salary);

当用户输入的姓名、地址、州、街道、城市或邮编对于您分配的空间而言太长时,将会发生可怕的事情。

【讨论】:

  • 感谢您的帮助。我现在正在应用所有内容!
  • 这个答案不太正确,因为代码仅使用链表中的-&gt;next 字段,并使用head 指向的位置作为输入字段,由用户填写。所以head指针的内容不会改变。
  • ??声明 head = head-&gt;next; 中的“头”发生了变化。 head 用作遍历列表的指针。列表本身不需要更改,这只是一个只读的 find()。
【解决方案2】:

您无法访问数据,因为在 INSERT 函数中,head 必须是一个 双指针,因为当您想在链表的头部插入一些东西时,您必须更改存储的地址在头。在您的代码中,您正在修改头部的副本。请记住,在 C 中一切都是为了价值而传递的。这意味着要修改指针中的地址内容,您必须在函数中传递指针的地址

【讨论】:

  • insert 将新员工添加到列表末尾。
  • 没有。他正在制作一个有序列表,有一段时间用于搜索新元素的放置位置。但是,如果想在列表末尾追加所有元素,他必须第一次修改头部的内容,所以我的解释仍然有效。
  • 作为使用双指针的替代方法,INSERT 可以返回指向第一个节点的指针(返回链表的头部)。
  • 那行不通。如果 malloc 在 INSERT 中失败,调用者可能会丢失整个列表
  • 因此,在您谈论 while(temp->next && name > newEmployee->name) {temp = temp->next;} 的解决方案中,他没有找到插入元素的位置。这太可怕了......(当然他必须在while中用strcmp()更改“>”)
猜你喜欢
  • 2017-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-12
  • 2020-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多