Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 函数更改其他变量的数据_C_Linked List_Structure - Fatal编程技术网

C 函数更改其他变量的数据

C 函数更改其他变量的数据,c,linked-list,structure,C,Linked List,Structure,我有一个结构旅行,我为这次旅行制作了一个链表,当我将旅行添加到列表中时,我没有问题,但是当添加第二次旅行时,它会覆盖第一次旅行。 我所做的输入是添加两个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

我有一个结构旅行,我为这次旅行制作了一个链表,当我将旅行添加到列表中时,我没有问题,但是当添加第二次旅行时,它会覆盖第一次旅行。 我所做的输入是添加两个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);//
}

代码中的一个问题是newTrip变量。您不能以尝试的方式将其添加到列表中。它是一个局部变量,位于主变量的一部分。因此,它超出了范围,即当您退出main的该部分时,它变得无效。我建议您重写createTripData,如下所示:

把它叫做:

    if (option == 1)
    {
        Trip* newTrip = createTripData();

        if(first == 1)
        {
            first = -1;
            trips = create_List(newTrip);
        }
        else
        {
            trips = add_List(trips, newTrip);
        }
    }
此外,您还可以通过处理add_list中的空列表来简化代码


函数:createTripData调用scanf,但无法检查返回值而不是参数值,因此如果用户只输入返回键或输入除数字以外的任何内容,则代码接受nothing输入,这是一个错误

函数:main有两个参数,但都没有使用。函数main有两个有效签名:

int main( int argc, char *argv[] )
int main( void )
由于未使用参数,代码应使用签名:

int main( void )
功能:main通过以下方式从用户处获取菜单选择:

scanf( "%d", &option );
但不检查返回值而不是参数值,因此当用户仅输入“返回”或数字以外的任何字符时,将使用字段选项中的先前值。如果用户输入除1或2以外的任何数字,则代码会在while循环中“尖叫”,不执行任何操作或按照变量选项中以前的值执行操作

也就是说,始终检查调用任何scanf系列函数的返回值并处理错误

在function:main中,假设用户输入了1或2。这不是一个有效的假设。永远不要相信用户会做正确的事情强烈建议用switch语句替换if option==1和if option==2,其中包含用户输入除1或2以外的任何数字时的adefault`case,即

switch( option )
{
    case 1:
        ...
        break;

    case 2:
        ...
        break;

    default:
        printf( "INVALID option: %d, valid options are 1, 2\n", option );
        break;
}
此字段位于结构列表的定义中

将变量命名为与变量类型相同的变量是非常糟糕的编程实践。一个可能的解决方案:

Trip *myTrip;
然后更新代码中的其他引用以使用myTrip

将变量命名为与变量类型相同的变量是非常糟糕的编程实践,唯一的区别是大小写。这种做法导致人们在阅读代码时感到困惑

函数中:创建\u列表调用malloc失败时会发生什么?一个空指针返回到function:add_List,它将该空指针返回到function:main,该函数是否成功覆盖变量trips中的值

声明:

fflush(stdin);
虽然允许在visual studio中使用,但不可移植。建议使用以下方法:

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
上述建议的方法会立即退出程序,留下操作系统来清理所有分配的内存,这可能是一种糟糕的编程实践,而不是编写一个循环来通知用户问题,清空stdin并允许用户重试

本声明:

printf("Select an option: \n 1-add new trip \n 2-Iterate\n");
如果菜单中有多个选项,阅读和理解将变得非常“困难”。建议使用C特性将所有连续字符串组合在一起,并编写如下语句:

printf("Select an option: \n"
       " 1-add new trip \n"
       " 2-Iterate\n");
注意:建议的格式还注意打印页面的右边缘,使布局更加美观

函数:delete_List从未调用,因此main中的“menu”缺少一个选项

顺便说一句:函数:delete_List使用递归,如果链表很短,则可以使用递归。但是,如果链表中有很多条目,那么特别是在windows上,堆栈溢出的可能性很高。我建议使用循环遍历链接列表,在保存->下一个指针后将每个条目传递给free,这样无论链接列表中有多少条目

为便于阅读和理解: 1.单独的代码块用于,if,else,while,do。。。while、switch、case、default通过单个空行 2.由2或3个空行分隔的功能应一致 3.遵循公理:每行只有一条语句,每条语句最多有一个变量声明

现在,你为什么看到你在问题中提到的问题:

传递给add_List的第二个指针指向main中堆栈上未初始化的本地指针,而不是指向链接列表的实际指针,该链接列表由:List*trips

建议使用唯一的名称,以便跟踪指向的内容

另外,在function:create_List中,新节点被设置为指向main中未初始化的指针,而不是指向main中trips中所需的条目

注意,在现代C编译器中,在function:main中 ,如果返回值始终为0,则不需要return语句

注意:语句return不是函数,因此除非将多个表达式包装到单个结果值中,否则不需要在return传回的值周围使用paren

为了简化,建议先删除变量,更改列表*行程;列出*trips=NULL;并将:iffirst==1替换为:if!旅行


也就是说,始终尝试编写仍能执行功能的最简单代码。

fflushstdin在除极少数实现外的所有实现中都是未定义的行为,并且不可移植。每当函数更改其他变量的数据时,这通常意味着您的写入超出了内存块的范围,很高兴地破坏了相邻变量的内存。仔细检查指针的使用情况和所做的取消引用。除非绝对需要,否则避免使用全局变量-此处不需要全局变量;在这个if块内。此外,您可以反复使用它。newTrip只是一个中间人,然后将行程添加到List*Trips中,但它的范围仅限于if块内。一旦退出if`块,存储在trips中的内存地址将被释放,以供系统重用,当然,系统在每次迭代中都会重复使用。因此,您可能最终将输入的所有值存储在同一地址,并在trips中分配该地址,这使得您试图访问超出if语句范围的内存地址,并立即进入未定义行为。此外,您根本不需要选项。只需初始化列表*trips=NULL;注意:“*”与变量一起使用,而不是与类型一起使用。然后,您只需要检查trips==NULL{..create 1st node..}否则{..add node to end..}非常感谢,之前我看到,即使在扫描新id时,也会更改列表中的id,即使我不使用add_List@HristoVutov-那是因为你使用了局部变量。这个答案每次分配一个新的行程,因此它不会发生。我知道这是复制,但最好显示List*trips=NULL;特别是在帮助新的C程序员时,因为在int*a,b,C;b和c当然不是指针。在类型上附加“*”会导致混淆,int*a、b、c;更不容易被误解。@DavidC.Rankin-我只是从OPs问题中抄来的。我没有注意到这件事。我认为你们不会达成共识@DavidC.Rankin IMO List*trips=NULL;很好,你应该避免写int*a,b,c;不管星星的位置如何
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");
printf("Select an option: \n"
       " 1-add new trip \n"
       " 2-Iterate\n");