【问题标题】:C linked list problemsC链表问题
【发布时间】:2017-12-03 23:50:02
【问题描述】:

我真的需要你的帮助来完成我的程序。我是 C 的新手,需要在我的项目中创建一个链表。

我在 macOS 上使用 xcode。 我的代码在这里:

typedef struct person
{
    char name[500];
    char telnum[16];
    char wohnort[500];
    struct person *next;

}person;

person *head=NULL;
void einlesen()
{
    person *p;
    char name[30];
    char telnum[16];
    char wohnort[30];
    //char buff1[15], buff2[15];
    int cnt=0;

    FILE *fp=fopen("Data2.txt", "r");
    if(fp==NULL)
    {
        printf("File konnte nicht geoeffnet werden!\n");
        exit(1);
    }
    while(fscanf(fp," %29[A-z ]\t%s\t%s", &name, &telnum, &wohnort)!=EOF)
    {

        cnt++;


        printf("Datei gefunden!\nDaten:%s, %s, %s\n", name, telnum, wohnort);


        if(head == NULL){
            head = (person*)malloc(sizeof(person));
            strcpy(head->name, name);
            strcpy(head->telnum, telnum);
            strcpy(head->wohnort, wohnort);
            head->next = NULL;
        }
        else{
            p = head;
            while(p->next != NULL)
            {
                p = p->next;
            }

            p->next = (person*)malloc(sizeof(person));
            strcpy(p->next->name,name);
            strcpy(p->next->telnum,telnum);
            strcpy(p->next->wohnort,wohnort);
            p->next->next = NULL;
        }

    }
    printf("Die Daten von %d Personen wurden eingelesen!\n\n", cnt);
    fclose(fp);
}

void addieren()
{   char name[30];
    char telnum[16];
    char wohnort[30];
    person *p = head;

    printf("Bitte den Namen der hinzufuegenden Person eingeben:\n");
    scanf(" %29s", name);
    while(getchar() != '\n');
    printf("\nBitte die Telefunnumer der hinzufuegenden Person eingeben:\n");
    scanf(" %15s", telnum);
    while(getchar() != '\n');
    printf("\nBitte den Wohnort der hinzufuegenden Person eingeben:\n");
    scanf(" %29s", wohnort);
    while(getchar() != '\n');

    if(p==NULL) return;
    while(p->next)
    {
        p=p->next;
    }
    p->next = (person*)malloc(sizeof(person));
    strcpy(p->next->name, name);
    strcpy(p->next->telnum, telnum);
    strcpy(p->next->wohnort, wohnort);
    p->next->next=NULL;
}

我的主要功能中有这个:

int main()
{   
    person *p1=head;


    einlesen();
    addieren();
    while(p1 !=NULL)
    {
        printf("Namen: %s\n", p1->name);
        p1=p1->next;
    }

    return 0;

}

它已经从文件中读取了数据,我想向它添加一些新记录并打印到屏幕上。这将返回 0 并且不会真正在屏幕上打印列表。

稍后我需要在我的程序中添加更多功能,例如: - 从列表中删除 -修改元素 - 在链表中搜索 - 保存到文件 -还有一个菜单

【问题讨论】:

  • 您在哪方面需要帮助?具体来说,您能否更新您的问题以包括:您希望该程序做什么?它实际上是做什么的?到目前为止,您做了什么(如果有的话)来尝试修复它?
  • 发布的代码缺少stdio.hstdlib.h 所需的#include 语句
  • @user3629249 代码开头有#include语句,只是这里没有贴出来。
  • @TimSweet 所以程序必须从我创建的文件中读取数据(确实如此),并且我想使用此功能将新记录添加到列表中。在我运行“addieren”(addtolist)函数后,我想将新列表打印到输出中以检查它是否正确添加了它
  • 关于:`while(fscanf(fp," %29[A-z ]\t%s\t%s", &name, &telnum, &wohnort)!=EOF)` 更好地检查成功而不是单一的故障模式。建议检查 (!=3)。 2) 当使用 '%s' 或 '%[...]' 输入说明符时,始终包含一个比输入缓冲区长度小 1 的 MAX CHARACTERS 修饰符。 a) 因为 NUL 字节将始终附加到输入数据和 b) 以避免任何缓冲区溢出的可能性。这种缓冲区溢出是未定义的行为,可能导致段错误事件。

标签: c data-structures struct linked-list


【解决方案1】:

我没有看到特别的问题,所以我将首先指出一些错误,也许当您添加一个问题(以问号结尾)时,您可以 ping 我以获取更新。

while(fscanf(fp," %29[A-z ]\t%s\t%s", &name, &telnum, &wohnort)!=EOF)

首先让我说我非常提倡在第一次使用函数之前阅读手册。事实上,我很确定这是我们作为程序员的期望。当然,我们必须了解要查找哪些手册,因为互联网是一个危险的地方,人们偶尔会撒谎。 OpenGroup 手册很好。例如,如果您在 Google 中输入“Opengroup fscanf”,您会找到fscanf 的手册,它会回答许多我的问题,当然……

手册指出,所有空白都被视为相同,作为尝试读取和丢弃尽可能多的空白的指令。因此,普通空格与格式说明符中的\t 具有相同的含义(至少在您的上下文中)......所以如果您的问题类似于“为什么所有空格都被同等对待?”那么答案是“因为这就是手册所说的应该做的。”

您正在阅读的固定宽度字段可能无法翻译,在这种情况下,手册还描述了在哪里测试的第一个字符不符合条件([A-z ],这看起来很可疑,你会可能通过阅读手册意识到这不是您想要的)。这将导致0 的返回值(来自scanf),在您的代码中,这看起来像是成功读取。

这是一个惯用的指南:让我们首先计算您想要读入的对象的数量...它们是从您的代码中逐字复制的:&name, &telnum, &wohnort...共有三个其中。

现在,取那个数字三,并将其与 fscanf 返回的值进行比较...如果这两个数字匹配,那么您可以安全地使用所有三个参数(尽管正如我在下面所指出的,它们可能不一定包含您希望它们包含的值)。

您也不应该在此处对nametelnumwohnort 使用&(地址)运算符。 char [10] 数组上的 address-of 运算符将产生一个 char (*)[10] 表达式,因为您肯定想要一个普通的 char * 表达式。因此,正确的做法是让 Cs 隐式“数组表达式到指针表达式”的转换为您完成。

下面可能更接近你想要的。我对[A-z ] 的建议是列出要包含在这些括号中的每个字符,或者如果要列出要排除的每个字符,请使用[^...]排除。需要明确的是,C 格式的字符串中没有 ranges ,以防你的问题是关于的。例如:

while(fscanf(fp," %29[qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM ] %s %s", name, telnum, wohnort)==3)

请注意,它还不完全存在。有可能将 32 字节输入中的 29 字节读入该固定宽度字段,从而在流中留下三个字符。也许它们不是空格,在这种情况下,您的空白指令将静默失败,剩下的三个字符将被视为telnum

您应该尝试在每次致电scanf 时仅阅读一个 项,前提是您了解相应的手册。


任何集合都不应该要求n 调用malloc 来存储n 对象。如果你设法完成这个(毫无疑问是自己分配的)任务,我建议你的下一个优先事项是将你的列表分配为每次调用malloc的多个节点...或者更好的是,你不必@ 987654345@每个字符串fscanf返回,你可以从相同的技术中受益;期望调用者分配列表,向您传递您需要的所有存储空间,以及从列表中添加、删除等的项目。该函数所做的只是修改传入的对象。


while(getchar() != '\n');

以上你认识到EOF 可能会发生...你认为getchar() 在发生这种情况时会返回什么?不是'\n',这是肯定的,它会无限期地返回那个(不是''\n')值,因此是一个无限循环。试图解决这个问题会使循环有点复杂。您需要存储角色,例如:

int c;
while ((c = getchar()) != EOF && c != '\n');

更清晰的替代方法实际上是使用fread,例如

char c;
while (fread(&c, 1, 1, stdin) && c != '\n');

不过,更好的是,根据手册的解释,使用fscanf(还有许多其他有用的功能供您阅读有关 A.S.A.P. 的信息)。连续输入十到十五次后,你认为你能记住这两行吗?

scanf("%*[^\n]");
getchar();

伙计...您的代码应该始终在使用 malloc 返回值之前检查它们。我们怎么知道您的malloc 电话没有返回NULL,从而导致您没有问过一个问题?

【讨论】:

    【解决方案2】:

    您正在函数 addieren 中创建一个新人,而不是接收您在 main 函数中创建的人。您需要将其作为参数接收,类似的东西

    int addieren(person **head) { ... }

    你应该做的主要是

    addieren(&p1);
    

    注意双指针,这样你就可以传递指针并在函数内部修改它。此外,您可能应该返回一个 int 来确认操作是否成功

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-29
      • 2013-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-03
      • 2011-05-16
      相关资源
      最近更新 更多