简体   繁体   English

C链表问题

[英]C linked list problems

I really need your help with my program. 我确实需要您的程序帮助。 I'm a newbie in C and need to create a linked list in my project. 我是C语言的新手,需要在我的项目中创建一个链表。

I use xcode on macOS. 我在macOS上使用xcode。 My code is here: 我的代码在这里:

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;
}

and i have this in my main function: 我的主要职能是这个:

int main()
{   
    person *p1=head;


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

    return 0;

}

It's already read the data from the file and I wanted to add some new records to it and the print to the screen. 它已经从文件中读取了数据,我想向其中添加一些新记录并将打印内容添加到屏幕上。 This returns 0 and doesn't really print the list on the screen. 这将返回0,并且实际上不会在屏幕上打印列表。

Later I need to add more functions to my program, like: -deletefromlist -modify element -search in the linked list -save to file -and a menue 稍后,我需要向程序中添加更多功能,例如:-deletefromlist -modify元素-在链接列表中搜索-保存到文件-以及菜单

You are creating a new person inside the function addieren instead of receiving the one you created on the main function. 您正在函数addieren中创建一个新人员,而不是接收您在主函数中创建的人员。 You need to receive it as an argument, something like that 您需要将其作为参数接收,像这样

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

And on the main you should make 而且主要是你应该

addieren(&p1);

Notice the double pointer so you can pass the pointer and modify it inside of the function. 注意双指针,因此您可以传递指针并在函数内部对其进行修改。 Also you probably should return an int to confirm either the operation was succesfull or not 另外,您可能应该返回一个int以确认操作是否成功

I see no particular question, so I'll start by pointing out some errors, and perhaps when you've added a question (which ends in a question mark) you can ping me for an update. 我看不到任何特定的问题,因此,我将从指出一些错误开始,也许当您添加了一个问题(以问号结尾)时,可以对我进行更新。

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

Let me just start off by saying I'm a huge advocate of reading the manual before using a function for the first time. 首先,我要说的是,我强烈建议在首次使用函数之前先阅读本手册。 In fact, I'm pretty sure it's expected of us, as programmers. 实际上,我非常确定这是我们作为程序员的期望。 Granted, we must learn which manuals to seek, because the internet is a dangerous place and people do occasionally lie. 当然,我们必须学习要寻找的手册,因为互联网是一个危险的地方,人们偶尔会撒谎。 The OpenGroup manuals are good. OpenGroup手册很好。 For example, if you type into Google "Opengroup fscanf", you'll find the manual for fscanf , which will answer many questions I', sure... 例如,如果您键入Google“ Opengroup fscanf”,则会找到fscanf的手册,该手册将回答我的许多问题,请确保...

The manual states that all whitespace is treated the same, as a directive which attempts to read and discard as much whitespace as possible. 该手册指出,所有空白都被视为相同的指令,它试图读取并丢弃尽可能多的空白。 Hence, a plain space has the same meaning to \\t in a format specifier (at least, in your context)... so if your question is something along the lines of "Why are all whitespaces treated the same?" 因此,在格式说明符中(至少在您的上下文中),普通空格与\\t含义相同...因此,如果您的问题与“为什么所有空白都被相同对待?”类似, then the answer is "because that's what the manual says it should do." 那么答案是“因为这就是手册说的应该做的”。

The fixed width field you're reading into can fail to translate, in a scenario the manual also describes where-by the first character tested failed to match the criteria ( [Az ] , which looks highly suspect, and you'll probably realise by reading the manual that this isn't what you want). 您正在阅读的固定宽度字段可能无法翻译,在这种情况下,手册还描述了测试的第一个字符与标准不符的地方( [Az ] ,这看起来很可疑,您可能会意识到阅读手册,这不是您想要的)。 That would result in a return value (from scanf ) of 0 , which, to your code, looks like a successful read. 这将导致返回值(来自scanf )为0 ,对您的代码而言,这看起来像是一次成功的读取。

Here's an idiomatic guideline: Let's first count the number of objects that you want to read into... Here they are, copied verbatim from your code: &name, &telnum, &wohnort ... There are three of them. 这是一条惯用的准则:让我们首先计算一下您想读入的对象的数量...在这里,从您的代码中逐字复制: &name, &telnum, &wohnort ...其中有三个。

Now, take that number, three, and compare it to what fscanf returns... If these two numbers match, then you can use all three arguments safely (though as I note below, they may not necessarily contain the values that you expect them to contain). 现在,取该数字(三个),然后将其与fscanf返回的值进行比较...如果这两个数字匹配,则可以安全地使用所有三个参数(尽管正如我在下面所述,它们不一定包含您期望的值)包含装有)。

You also shouldn't use the & (address-of) operator here for name , telnum or wohnort . 您也不应在此处使用& (address-of)运算符来输入nametelnumwohnort The address-of operator on a char [10] array would result in a char (*)[10] expression, where-as you most certainly want a plain vanilla char * expression. char [10]数组上的address-of运算符将导致char (*)[10]表达式,而-您最想确定的是纯香草char *表达式。 Hence, the correct thing to do is to let Cs implicit "array expression to pointer expression" conversion do that for you. 因此,正确的做法是让Cs隐式的“数组表达式到指针表达式”的转换为您完成。

Below is probably closer to what you want. 以下可能更接近您想要的。 My advice regarding the [Az ] thing is that you list out each of the characters you want to include in those brackets, or use [^...] if you want to list out each of the characters you want to exclude . 我对[Az ]的建议是,列出要括在方括号中的每个字符,如果要列出要排除的每个字符,请使用[^...] To be clear, there are no ranges in C format strings, in case that's what your question was about. 需要明确的是,如果您要问的是C格式字符串,则没有范围 eg: 例如:

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

Note that it isn't quite there, yet. 请注意,它还不存在。 There's the potential for 29 bytes of a 32 byte input to be read into that fixed width field, leaving three characters on the stream. 有可能将32字节输入中的29字节读入该固定宽度字段,从而在流上留下三个字符。 Perhaps they're not space, in which case your whitespace directive will silently fail, and those remaining three characters will be treated as telnum . 也许它们不是空格,在这种情况下,您的空白指令将以静默方式失败,而其余三个字符将被视为telnum

You should try to read just one item per call to scanf , if only until you understand the corresponding manual. 您应该尝试在每次调用scanf时仅读取一项 ,直到理解相应的手册为止。


No collection should ever require n calls to malloc to store n objects. 任何集合都不应要求n调用malloc来存储n对象。 If you manage to complete this (no doubt self-assigned) task, I suggest making it your next priority to allocate your list as multiple nodes per call to malloc ... or better yet, the convenience you get not having to free() every string fscanf returns , you could benefit from the same technique; 如果您设法完成此任务(毫无疑问是自赋值的),我建议将您的列表作为下一个优先事项,以对malloc每次调用将列表分配为多个节点……或者更好的是,不必获得free()的便利性fscanf 返回的每个字符串,您都可以从相同的技术中受益; expect caller to allocate the list, passing you all the storage you need, as well as items to add, remove, etc from the list. 希望调用者分配列表,将您所需的所有存储以及要添加,删除的项目传递给您。 All the function does is modify the objects passed in. 该函数所做的全部就是修改传入的对象。


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

Above you recognise that EOF can occur... what do you think getchar() will return when that happens? 在上面,您认识到EOF可能发生...当发生这种情况时,您认为getchar()将返回什么? Not '\\n' , that's for sure, and it'll keep returning that (not `'\\n') value indefinitely, hence an infinite loop. 可以肯定,不是'\\n' ,它会无限期地返回该值(而不是'\\ n'),从而导致无限循环。 Trying to solve this problem complicates the loop a bit; 试图解决这个问题会使循环变得有些复杂。 you need storage for the character, eg: 您需要为角色存储,例如:

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

The clearer alternative to that is actually to use fread , eg 实际上,更清晰的选择是使用fread ,例如

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

Nonetheless, better yet, is using fscanf , according to how the manual explains (there are many other useful functionalities for you to read about ASAP). 但是,根据手册的说明,更好的方法是使用fscanf (还有许多其他有用的功能可供您阅读有关ASAP的信息)。 Do you think you can remember these two lines, after typing them ten or fifteen times in a row? 连续键入十或十五次后,您是否还记得这两行?

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

Man... your code should always check malloc return values before they're used. ......您的代码应始终在使用它们之前检查malloc返回值。 How do we know your malloc calls aren't returning NULL , leading to a question which you haven't asked? 我们怎么知道您的malloc调用没有返回NULL ,从而导致您没有问过一个问题?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM