我有结构Trip和我为这次旅行制作链接列表,当我添加到列表的旅行时我没有问题,但是当添加第二次旅行时它会覆盖第一次旅行。 我做的输入是添加两个id为1和2的行程,当我迭代它们时,我看到有两次id 2
#include <stdio.h>
#include <stdlib.h>
char date[10];
char date2[10];
char newdate[10];
char newdate2[10];
int i,t,i2,t2;
int ret;
int option;
typedef struct trip
{
int code;
char startdate[10];
int duration;
double price;
} Trip;
typedef struct list
{
Trip* Trip;
struct list* next;
} List;
List* create_List(Trip* trip)
{
List* newList = malloc(sizeof(List));
if (NULL != newList)
{
newList->Trip = trip;
newList->next = NULL;
}
return newList;
}
void delete_List(List* oldList)
{
if (NULL != oldList->next)
{
delete_List(oldList->next);
}
free(oldList);
}
List* add_List(List* wordList, Trip* trip)
{
List* newList = create_List(trip);
if (NULL != newList)
{
newList->next = wordList;
}
return newList;
}
void createTripData(Trip *trip);
int main(int argc, char *argv[])
{
List* trips;
int first = 1;
while(1)
{
printf("Select an option: \n 1-add new trip \n 2-Iterate\n");
scanf("%d", &option);
if (option == 1)
{
Trip newTrip;
createTripData(&newTrip);
if(first == 1)
{
first = -1;
trips = create_List(&newTrip);
}
else
{
trips = add_List(trips, &newTrip);
}
}
else if (option == 2)
{
system("@cls||clear");
List* iter;
for (iter = trips; NULL != iter; iter = iter->next)
{
printf("Id %d \n", iter->Trip->code);
}
}
}
return (0);
}
void createTripData(Trip *trip)
{
fflush(stdin);
printf("Enter id: ");
scanf("%d", &trip->code);//
}
答案 0 :(得分:0)
函数:createTripData()调用scanf()
但未能检查返回的值(而不是参数值),因此如果用户只输入一个返回键或输入除数字之外的任何内容,则代码接受什么都没输入,这是一个错误
函数:main()
有两个参数,但都没有使用。函数main()
有两个有效签名:
int main( int argc, char *argv[] )
int main( void )
由于未使用参数,代码应使用签名:
int main( void )
功能:main()
通过以下方式从用户处获取菜单:
scanf( "%d", &option );
但不检查返回的值(不是参数值),因此当用户只输入“返回”时或者除了数字之外的任何字符,使用字段option
中的先前值。如果用户输入除1或2之外的任何数字,那么代码会尖叫&#39;通过while()
循环,在变量option
中执行任何操作或以前的值。
即。始终检查从任何scanf()
系列函数调用返回的值并处理错误。
:main()
,假设用户输入了1或2.这不是一个有效的假设。 (永远不要相信用户做正确的事情)强烈建议if( option == 1
和else if(option == 2)
替换为switch() statement that includes a
默认情况,以便用户输入除1或2 IE以外的任何数字
switch( option )
{
case 1:
...
break;
case 2:
...
break;
default:
printf( "INVALID option: %d, valid options are 1, 2\n", option );
break;
}
此字段,在struct list
Trip* Trip;
将变量命名为与变量类型相同的编程实践是非常糟糕的。一个可能的解决方法:
Trip *myTrip;
然后更新代码中的其他引用以使用myTrip
将变量命名为与变量类型相同的编程实践是非常糟糕的,唯一的区别是大写。这种做法导致人们在阅读代码时感到困惑。
在功能中:create_list()
当对malloc()
的调用失败时会发生什么?函数返回NULL指针:add_List()
返回指向函数的NULL指针:main()
,其中(成功与否)覆盖变量trips
中的值。
fflush(stdin);
虽然在视觉工作室被允许,但是不便携。建议使用类似的东西:
int ch;
while( (ch = getchar()) != EOF && '\n' != ch );
关于对scanf()
的调用,以下是处理错误事件的一种方法:
if( 1 != scanf( "%d", &trip->code ) )
{ // then error occurred as 'scanf' returns number of successful input/conversions
perror( "scanf for code failed" );
exit( EXIT_FAILURE );
}
// implied else, scanf successful
以上建议的方法立即退出程序(让操作系统清理所有已分配的内存,这将是糟糕的编程习惯)您可能希望代替一个循环,通知用户问题,清空标准输入并允许用户再试一次。
这句话:
printf("Select an option: \n 1-add new trip \n 2-Iterate\n");
将变得非常困难&#39;阅读并理解菜单中是否有多个选项。建议使用C功能将所有连续字符串组合在一起并编写如下语句:
printf("Select an option: \n"
" 1-add new trip \n"
" 2-Iterate\n");
注意:建议的格式也注意打印页面的右边缘,使布局更好。
功能:delete_List()
永远不会被调用,所以&#39;菜单&#39;在main()
中缺少选项。
BTW:函数:delete_List()
使用递归,如果链表很短,则可以。但是,如果链接列表中有很多条目(特别是在Windows上),则堆栈溢出的可能性很高。我建议使用循环来遍历链表,在保存free()
指针后将每个条目传递给->next
然后链表中有多少条目无关紧要
为便于阅读和理解: 1.通过一个空白行分隔代码块(for,if,else,while,do ... while,switch,case,default) 2.通过2或3个空行分隔功能(保持一致) 3.遵循公理:每行只有一个语句,并且(最多)每个语句一个变量声明。
现在,您为什么要看到问题中提到的问题:
传递给add_List()
的第二个指针是main()
中堆栈上未初始化的本地指针,而不是指向由List* trips;
声明的链表的实际指针
建议使用唯一名称,以便您可以跟踪指向什么的内容。
此外,在函数:create_List()
中,新节点被设置为指向main()中的未初始化指针,而不是指向main中trips
中的所需条目。
注意,在函数:main()
中,在现代C编译器中,如果返回值始终为0,则不需要return
语句。
注意:语句return
不是函数,因此没有必要(除非将多个表达式包装到单个结果值中)以使return
传回的值有parens。
为简化起见,建议删除变量first
,将List* trips;
更改为List *trips = NULL;
并将if(first == 1)
替换为:if( !trips )
即。总是尝试编写仍然执行功能的最简单的代码。