【问题标题】:C programming printing a linked list, not moving along list and crashingC编程打印一个链表,不沿着列表移动并崩溃
【发布时间】:2015-03-01 06:31:21
【问题描述】:

我正在尝试打印一个链表,它的行为很奇怪,当它假设移动到下一个项目时它不会,例如打印的第一个项目是“Granny Smith”,然后是结构中的其余部分,当它进入下一行时,应该是新食物是“兰尼史密斯”总是没有 G,其他大部分细节都被破坏或胡言乱语。任何帮助将不胜感激。

#define _CRT_SECURE_NO_WARNINGS

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

#define cls system("cls");
#define flush fflush(stdin)
#define pause system("pause");


struct food  // Declaration of struct
{
    char produce[20];
    char type[20];
    char soldBy[20];
    float price;
    int quantityInStock;
    struct food *next;
};


void addPres(struct food** tip, char tokenPro[20], char tokenType[20], char tokenSold[20], float tokenFloat, int tokenInt);
void display ();
void displayMenu ();
int getChoice ();
void readDataIn();




int main()
{
    int choice = 0;
    int ;
    struct food first;
    char *saveFloat, *saveInt;
    char tokenPro[20], tokenType[20], tokenSold[20], savePro[20], saveType[20], saveSold[20], j[1900];
    float tokenFloat, messFloat;
    int danint, tokenInt;
    struct food* a = NULL;
    FILE* file;

    a = NULL; // sets the first item on the list to empty

//readDataIn();
    do
    {
        choice = getChoice();//function to present choices and receive an answer
        switch (choice)//switch routes the choice
        {
        case 1: //to enter a new node on the list
            cls;
            printf("Enter the produce type: ");
            fgets(tokenPro, 20, stdin);
            printf("Enter the type: ");
            fgets(tokenType, 20, stdin);
            printf("Enter the units of measurement: ");
            fgets(tokenSold, 20, stdin);
            printf("\nEnter the price per %s: ", &tokenSold);
            scanf("%f", &tokenFloat );
            printf("\nEnter the quantity in stock: ");
            scanf("%i", &tokenInt );
            //pause;
            addPres(&a, tokenPro, tokenType, tokenSold, tokenFloat, tokenInt);
            break;
        case 2: //to display the linked list
            display(a);

            break;
        case 3: //to reverse the order

            if((file=fopen("AssignmentTwoInput.txt", "r")) != NULL)  //opens files
            {
                while(fgets(j, sizeof(j), file))  //while information is being sent to j from the file
                {
                    strcpy(savePro, strtok(j, ","));
                    strcpy(saveType, strtok(NULL, ","));
                    strcpy(saveSold, strtok(NULL, ","));
                    saveFloat = strtok(NULL, ",");
                    saveInt = strtok(NULL, "\n");
                    messFloat = atof(saveFloat); //ID number is assigned to token2
                    danint = atoi(saveInt); //converts  the value token2 points to into an int (previously read in as an string)
                    addPres(&a, savePro, saveType, saveSold, messFloat, danint); //sends the name and ID to the function to add a person
//printf("\n %s \t %s \t %s \t %f \t %i", savePro, saveType, saveSold, messFloat, danint);
//pause;
                }//end while loop
            }//end if loop
            printf("\nSuccessfully loaded input file\n\n\n"); //message to tell user the back was found and imported successfully
            pause;
            fclose(file);
            break;
        case 4: //to export data

            break;
        case 5: //option to exit

            exit(0);
            break;
        default://error checking
            printf("Please enter a valid choice.\n");
            break;
        }//switch loop close

    }
    while (choice != 5);   //end menu choices


    return 0;
}//end main


void addPres(struct food** tip, char tokenPro[20], char tokenType[20], char tokenSold[20], float tokenFloat, int tokenInt)
{


    struct food* temp =

        (struct food*) malloc(sizeof(struct food));
    strcpy(temp->produce, tokenPro);
    strcpy(temp->type, tokenType);
    strcpy(temp->soldBy, tokenSold);
    temp->price = tokenFloat;
    temp->quantityInStock = tokenInt;

//printf("\n %s \t %s \t %s \t %f \t %i", temp->produce, temp->type, temp->soldBy, temp->price, temp->quantityInStock);
//pause;
    if (tip == NULL) //if the tip node is empty
    {
        tip = temp; //tip node becomes this node
        (*tip)->next = NULL; // since there are no others yet the next node will be empty
    }


    else
    {
        temp->next = tip; // reassigns the tip node to the next one
        (*tip) = temp; //inserts current node as the tip
    }
}

void display(struct food* c)
{
//c = first; //assigns c to the first node on the linked list
    int count = 1;
    struct food *temp;
    temp = c;
    cls;
    printf("==========================================================================\n"); //prints a header to say which info is which
    printf(" Item #   Produce       Type             Sold By         Price    In Stock\n");
    printf("==========================================================================\n");
    while( c != NULL)
    {
        printf("%3i \t", count);
        printf("%s \t", c->produce ); //prints name
        printf("%s \t", c->type ); //prints name
        printf("%s \t", c->soldBy); //prints name
        printf("%-3.2f \t", c->price); //prints ID
        printf("%i\n", c->quantityInStock); //prints ID
        pause;
        count = count + 1;
        c = c->next; //advances to next item in the linked list

        if(c == NULL)
        {
            printf("\n end \n"); //once end is found user is told

            pause;
        }
    }
    printf("\n done \n");
    pause;
}//end display

【问题讨论】:

  • 这个fflush(stdin) 是未定义的行为,fflush() 是用于输出流......而system("PAUSE") 是一个只有windows 无用的东西,使用真正的终端仿真器并在那里执行程序,这样你不需要那些古怪的把戏。
  • 开启警告,注意指针类型不兼容的信息。

标签: c list printing


【解决方案1】:

你有三个重要的错误,其中一个似乎是由于复制和粘贴一些代码造成的,

  1. 这个printf() 语句会导致未定义的行为

    printf("\nEnter the price per %s: ", &tokenSold);
    

    因为您传递了正确的地址但指针类型错误,所以指针算术将导致 printf() 内部的未定义行为

    printf("\nEnter the price per %s: ", tokenSold);
    /* remove the & --------------------^ here */
    
  2. 您将双指针传递给addPres,但您从未取消引用它来访问实际的指针,这是您要修改的内容,这会导致未定义的行为和空列表的观察效果,​​因为一旦函数返回它并没有改变原来的指针,你应该在这个函数中使用解引用运算符访问双指针,例如,而不是

    if (tip == NULL)
    

    应该是的

    if (*tip == NULL)
    

    这同样适用于该函数内的每个访问。

    • 我怎么这么快就发现了所有这些问题?

      因为我在编译您的程序时启用了编译器警告并且它开始显示这些问题。

    • 你的代码会不会有其他问题?

      可能是的,但您需要先解决这些问题。

  3. fflush(stdin),一个非常常见的错误,似乎来自一些教程或书籍或在线资源,标准明确指出fflush() 用于输出流,而输入流的行为未定义,以下是取自 C11 草案

    7.21.5.2 fflush 函数

    1. 如果流指向输出流或更新流,其中最近的 未输入操作,fflush 函数会导致该流的任何未写入数据 被交付到宿主环境中写入文件;否则,行为未定义。

【讨论】:

  • 非常感谢!现在可以了,而且 fflush(stdin) 是我的第一位老师教我的,他不是很好,这一点很明显。
  • @user2603473 在成为这个网站的活跃会员之前我不知道,但是有很多糟糕的c老师或书籍以及在线课程和教程,很多。跨度>
  • @user2603473 你的老师告诉你MSDN compiler,其中fflush(stdin) 是完全定义的(作为该平台上的非标准扩展)-- 如果流是开放输入, fflush 清除缓冲区的内容。
  • @GrijeshChauhan 有趣,我不知道,但是 c 老师不应该教非标准编译器特定的功能。你怎么看?
  • @iharob 教授和使用像 MSDN 这样的非标准编译器并没有错。我相信 OP 的课程更多是关于编程而不是 C,而且教师只有有限的时间来互动和传授知识,学生有责任从书本中进一步深入探索。如果有人真的担心——“为什么标准没有定义fflush(stdin)”可能是一个很好的科学问题?在可能的地方。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多