函数更改其他变量的数据

时间:2017-05-11 14:49:26

标签: c linked-list structure

我有结构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);//
}

1 个答案:

答案 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 == 1else 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 )

即。总是尝试编写仍然执行功能的最简单的代码。