【问题标题】:Getting infinite loop after entering 2 objects to the linked list in C将2个对象输入C中的链表后出现无限循环
【发布时间】:2021-08-17 10:30:27
【问题描述】:

我正在尝试创建一个汽车租赁项目。我在函数createCarList() 中创建了一个链表,其中struct carf.h 中定义。 当我进入一辆车时,一切正常。当我输入两辆车时,我总是会出现无限循环,例如使用printAllCars() 打印列表时,或者如果我尝试检查该车是否已经在列表中。

这是我的代码:

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



/*car struct */

typedef struct car{
    unsigned int plate_number;
    unsigned int vin_number;
    char *Manufacturer_Name;
    char *model;
    char *colour;
    unsigned int year_Manufactured;
    unsigned int realseYear;
    unsigned int payment;
    unsigned int value;
    unsigned int engine_power;
    struct car *next;

}car;

car *cars;

/*function to scan and check the int input*/
int CheckIntinput(unsigned int *a)
{

    char temp[20];
    int i;
    int flag=1;
    while(1)
    {
    scanf("%s",temp);
    for(i=0;i<strlen(temp);i++)
    {
        if(!isdigit(temp[i]))
        {
            flag=0;
            printf("You did not enter a number , Please enter an argument's number\n");
            break;
        }
    }
    if(flag)
    {
        break;
    }
    flag=1;
  }
    
    *a=strtoul(temp,NULL,10);
    return 1;
}

/*function to check if the information of the car are correct*/
void checkifcarnputiscorrect(unsigned int *plate_number,unsigned int *vin_number,unsigned int *year_Manufactured,unsigned int *realseYear
,unsigned int *payment,unsigned int *value,unsigned int *engine_power){
    int flag=1;

     while(1)
     {
        printf("enter plate number :");
        CheckIntinput(plate_number);
        if(*plate_number>9999999 || *plate_number<1000000)
         {
            printf("plate number should be 7 digits try again \n");
            flag=0;
         }
         /*
         if(!checkifcaralreadyinlist(*plate_number))
            {
                printf("the car is already in the list \n");
                flag=0;
            }*/
         if(flag){break;}
         flag=1;
     }

     while(1)
     {
         printf("enter vin number :");
         CheckIntinput(vin_number);
     if(*vin_number>99999 || *vin_number<10000)
     {
         printf("vin_number should be 5 digits try again\n");
         flag=0;
     }
     if(flag){break;}
     flag=1;
     }

    while(1)
    {
        printf("enter year manfucatured :");
        CheckIntinput(year_Manufactured);
     if(*year_Manufactured>9999||*year_Manufactured<1000)
     {
         printf("yeaer_manfucatured should be 4 digits try again\n");
         flag=0;
     }
     if(flag){break;}
     flag=1;
    }

    while(1)
    {
        printf("enter realese year :");
        CheckIntinput(realseYear);
     if(*realseYear>9999||*realseYear<1000){
         printf("realse year  should be 4 digits try again \n");
        flag=0;
     }
     if(flag){break;}
     flag=1;
    }

    while(1){
        printf("enter payment :");
       CheckIntinput(payment);
     if(*payment>9999999||*payment<0){
         printf("payment should be between 0-9999999 digits\n");
         flag=0;
     }
     if(flag){break;}
     flag=1;
    }

    while(1){
        printf("enter value :");
        CheckIntinput(value);
     if(*value>9999999||*value<0){
         printf("value should be between 0-9999999 digits\n");
         flag=0;
     }
     if(flag){break;}
     flag=1;
    }

    while(1){
        printf("enter engine_power :");
       CheckIntinput(engine_power);
     if(*engine_power>9999||*engine_power<1000){
         printf("engine power be 4 digits\n");
         flag=0;
     }
     if(flag){break;}
     flag=1;
}
}

/*function to scan and check if the input is only chars*/
void Checkstringifonlychars(char *str){
    int i;
    int flag=1;
   while(1)
   {
       scanf("%s",str);
       for(i=0;i<strlen(str);i++)
       {
           if(!isalpha(str[i]))
           {
               flag=0;
               printf("wrong input try input only chars.");
               break;
           }
       }
       if(flag)
       {
           break;
       }
       flag=1;
   }
   
   
}



int CheckLonginput(unsigned long *a)
{

    char temp[20];
    int i;
    int flag=1;
    while(1)
    {
    scanf("%s",temp);
    for(i=0;i<strlen(temp);i++)
    {
        if(!isdigit(temp[i]))
        {
            flag=0;
            printf("You did not enter a number , Please enter an argument's number\n");
            break;
        }
    }
    if(flag)
    {
        break;
    }
    flag=1;
  }
    
    *a=strtoul(temp,NULL,10);
    return 1;
}

/*creating empty car list */


int createCarList()
{
    car *cars=(car*)malloc(sizeof(car));
    if(!cars)
    {
        return 0;
    }
    cars->next=NULL;
    return 1;
}

int addNewCar()
{
    unsigned int plate_number,vin_number,realseYear,year_Manufactured,payment,value,engine_power;
    char *Manufacturer_Name,*model,*colour,c;
    car * temp=NULL;
    car * p=NULL;
    temp=NULL;
    temp=(car*)malloc(sizeof(car));
    while(1){
        checkifcarnputiscorrect(&plate_number,&vin_number,&year_Manufactured,&realseYear,&payment,&value,&engine_power);

        Manufacturer_Name=(char*)malloc(5 * sizeof(char));
        printf("enter Manufacturer Name:");
        Checkstringifonlychars(Manufacturer_Name);
    
        model=(char*)malloc(5 * sizeof(char));
        printf("enter model:");
        Checkstringifonlychars(Manufacturer_Name);
    
        colour=(char*)malloc(5 * sizeof(char));
        printf("enter colour of the car:");
        Checkstringifonlychars(Manufacturer_Name);
    
        temp->plate_number=plate_number;
        temp->vin_number=vin_number;
        strcpy(temp->Manufacturer_Name,Manufacturer_Name);
        strcpy(temp->model,model);
        strcpy(temp->colour,colour);
        temp->year_Manufactured=year_Manufactured;
        temp->realseYear=realseYear;
        temp->payment=payment;
        temp->value=value;
        temp->engine_power=engine_power;
        temp->next=NULL;

        if(cars==NULL)
        {
            cars=temp;
        }
        else
        {
            p=cars;
            while(p->next!=NULL)
            {
                p=p->next;
            }
            p->next=temp;
        }  

        printf("\n done adding? if yes press y ");
        scanf(" %c",&c);
        if(c=='y')
        {
            break;
        }

   
    }
    if(cars==NULL)
    {
        return 0;
    }
    return 1;
}



void printAllCars(void){

    car *tmp=cars;

    if(!cars){ 
        printf("No Cars in list to Shown\n");
        return;
    }
    
    printf("\nCar List :\n\n");
    printf("LicenseNum | chassisNum | makerName | modelName | color | productionYear | onRoadYear |  price  |  paidMoney  | engine");
    printf("\n----------------------------------------------------------------------------------------------------------------------\n");
    while(tmp!=NULL)
    {
        printf("%-11u ",tmp->plate_number);
        printf("%-13u ",tmp->vin_number);
        printf("%-11s ",tmp->Manufacturer_Name);
        printf("%-11s ",tmp->model);
        printf("%-7s ",tmp->colour);
        printf("%-16u ",tmp->year_Manufactured);
        printf("%-11u ",tmp->realseYear);
        printf("%-9u ",tmp->value);
        printf("%-14u ",tmp->payment);
        printf("%u\n",tmp->engine_power);
        tmp=tmp->next;
    }

    printf("\n");
}

int main()
{
    createCarList();
    addNewCar();
    printAllCars();
    return 0;
}

输入:

enter plate number :1234567
enter vin number :12345
enter year manfucatured :1994
enter realese year :1995
enter payment :30000
enter value :25000
enter engine_power :3000
enter Manufacturer Name:bmw
enter model:bmw
enter colour of the car:red

输出:

plate number :1234567
vin number :12345
year manfucatured :1994
realese year :1995
enter payment :30000
enter value :25000
engine_power :3000
Manufacturer Name:bmw
model:bmw
colour of the car:red

当我添加第二辆车或更多时。

enter plate number :1234567
enter vin number :12345
enter year manfucatured :1994
enter realese year :1995
enter payment :30000
enter value :25000
enter engine_power :3000
enter Manufacturer Name:bmw
enter model:bmw
enter colour of the car:red

输出: 打印第一辆车然后无限时间第二辆车。

我检查了所有函数的while 循环,但找不到错误。可能是什么问题?

【问题讨论】:

  • createCarList 创建一个局部变量cars,返回时会丢失
  • ... 这让我怀疑提供的代码不能代表真正的问题。
  • 请提供问题的minimal reproducible example 准确输入、预期输出和实际输出。
  • car * temp=NULL; temp=NULL; temp=(car*)malloc(sizeof(car)); 中间没有阅读?你为什么不只是有car* temp = (car*)malloc(sizeof(car));
  • 如果我从输入中获得 1 辆汽车,它可以使用输入中的特定详细信息打印汽车,我在这里没有写的所有功能都可以正常工作,但是当我输入 2 辆以上汽车时存在问题,它在开始打印时进入无限循环,并且不会停止

标签: c linked-list


【解决方案1】:

我在您的代码中发现了 5 个错误。修复这些错误后,您的程序似乎可以工作。不过,我还没有测试过所有类型的输入。


第一个错误:

在函数createCarList中,一行

car *cars=(car*)malloc(sizeof(car));

不写入您的全局变量cars。相反,它使用该名称创建一个新的局部变量,并改为写入该变量。如果你想写全局变量,你应该写cars=(car*)malloc(sizeof(car));。但是,我认为这没什么意义,因为这只会使cars 指向一个大部分未初始化的节点。最好完全删除函数createCarList


第二个错误:

在函数addNewCar的行中

model=(char*)malloc(5 * sizeof(char));
printf("enter model:");
Checkstringifonlychars(Manufacturer_Name);

您需要将Manufacturer_Name 替换为model。您稍后在使用变量colour 的代码中犯了同样的错误:

colour=(char*)malloc(5 * sizeof(char));
printf("enter colour of the car:");
Checkstringifonlychars(Manufacturer_Name);

第三个错误:

在函数addNewCar的行中

strcpy(temp-&gt;Manufacturer_Name, Manufacturer_Name);

您写入未初始化指针temp-&gt;Manufacturer_Name 的地址,导致undefined behavior。您必须首先为新字符串分配内存(例如malloc)并让temp-&gt;Manufacturer_Name 指向该内存。但是,由于您已经为 Manufacturer_Name 这样做了,因此不使用 strcpy 可能就足够了,而是简单地复制指针,如下所示:

temp-&gt;Manufacturer_Name = Manufacturer_Name;

以下几行与上面描述的问题相同:

strcpy(temp->model,model);
strcpy(temp->colour,colour);

第四个错误:

随行

Manufacturer_Name = (char*)malloc(5 * sizeof(char));

您为 5 个字符分配空间,包括终止的空字符。由于您使用%sscanf 格式说明符,如果用户输入"Honda",这将导致buffer overflow,因为存储该字符串需要6 个字节,包括终止空字符。这种缓冲区溢出会导致未定义的行为。因此,不要使用该行读取输入

scanf("%s",str);

最好用

scanf("%4s",str);

将输入限制为 4 个字符,因此不会发生缓冲区溢出。


第五个错误:

在函数addNewCar中,一行

temp = (car*)malloc(sizeof(car));

只执行一次,因为它在while 循环之外。您必须将其移动到 while 循环内,以便为每添加一辆车执行一次。否则,您的程序将为每个链表节点重用相同的内存地址,以便每个节点都指向自己。这将在稍后打印出函数printAllCars 中的节点时导致无限循环。


其他问题:

  • 函数CheckIntinputcheckifcarnputiscorrectCheckstringifonlycharsCheckLonginput 具有误导性名称。在这种情况下,“检查”一词意味着函数仅执行输入验证,而不是函数实际读取输入。
  • 不检查返回值就使用scanf 是不安全的。此外,对于基于行的输入,我建议您始终使用fgets 而不是scanf。有关详细信息,请参阅此页面:A beginners' guide away from scanf()
  • 您应始终检查malloc 的返回值,以验证它不是NULL
  • 您不需要强制转换 malloc 的结果。您可能想阅读以下问题:Do I cast the result of malloc?

【讨论】:

  • 感谢那些错误,其中一些只是因为我在编写代码时复制和粘贴,当我尝试打印链接列表时我仍然没有解决的问题我仍然得到无限循环并开始打印链表中的最后一个元素没有停止
  • @am_sa:我无法重现您的问题,因为在我的计算机上,由于上​​述第三个错误,您的程序预先崩溃了。由于某些提到的错误会导致未定义的行为,因此它们可能是您的问题的原因。未定义的行为可能导致任何事情发生。因此,我建议您首先修复所有提到的错误,如果仍然存在问题,您可以发布更新的代码。但是,不要覆盖原始问题,因为这会使我的答案无效。您可以将更新后的代码添加到问题的底部。
  • 我在修复错误后更新了...到编译器我总是使用 :gcc mySource.c -ansi -Wall -pedantic-errors -lm -o myProg ...它适用于 1 个对象在链表中,但进入第二个时总是无限循环
  • @am_sa:当我现在在 Windows 上使用 Microsoft Visual Studio 运行您的程序时,由于“第一个错误”中提到的问题,它现在崩溃了。您的函数createCarList 使cars 指向大部分未初始化的节点。所有节点内容都未初始化,next 指针除外。这稍后会导致printAllCars 崩溃。如果我只是删除对createCarList 的函数调用,程序将停止崩溃,我现在能够第一次重现您在问题中提到的问题。我现在正在使用我的调试器调查这个问题。
  • @am_sa:使用调试器,我能够找到问题所在。我现在在我的答案中添加了“第五个错误”。
猜你喜欢
  • 2013-04-26
  • 1970-01-01
  • 1970-01-01
  • 2021-03-12
  • 1970-01-01
  • 1970-01-01
  • 2014-12-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多