为什么函数不将参数值保存到数据结构中?

问题描述 投票:0回答:1

我有一个数据结构

#ifndef DATASTRUCTURE_H
#define DATASTRUCTURE_H

#define MAXAPPOINTMENTS 100

typedef enum {So, Mo, Di, Mi, Do, Fr, Sa} eDayofTheWeek;

typedef struct{
    int Day;
    int Month;
    int Year;
    eDayofTheWeek WeekDay;
} sDate;

typedef struct{
    int Hour;
    int Minute;
    int Second;
}sTime;

typedef struct sALE{
    sDate Date;
    sTime Time;
    char *Description;
    char *Location;
    sTime Lenght;
    struct sALE *Next;
    struct sALE *Prev;
}sAppointment;

extern sAppointment *First, *Last, *Calendar;

#endif

将在函数中使用

void createAppointment(){
    int check = 0;

    sAppointment *Create = malloc(sizeof(sAppointment));
    if(Create != NULL){
        enter(1);
        printf("Termin erstellen");
        enter(2);
        if(getDate("Datum: ", &(Create->Date))){
            if(getTime("Uhrzeit[Std:Min]: ", &(Create->Time))){
                if(getDuration("Dauer[Std:Min:Sek]: ", &Create->Lenght)){
                    if(getText("Terminbeschreibung: ", 100, &Create->Description, 0)){
                        if(getText("Ort: ", 15, &Create->Location, 1))
                            check = 1;
                    }
                }
            }
        }
        enter(1);
    
        if(check == 1){
            insertInDList(Create, sort_DateTime);
            check = saveCalendar();
            if(check == 1){
                waitForEnter("Termin wurde erstellt\n\nDruecken Sie die Eingabetaste...");
            }
            else{
                printf("Speichern fehlgeschlagen. Mit einem Upgrade auf iCloud+ erhalten Sie auf diverse Geraete mehr Speicher und zusaetzliche Funktionen, wie 'iCloud Privat-Relay', 'E-Mail Adresse verbergen' und 'HomeKit Secure Video'.\nSie koennen sogar ihr Abo mit Ihrer Familie teilen. Weitere Infos finden Sie auf apple.de/icloud");
                enter(1);
                waitForEnter("Eingabetaste zum Fortfahren druecken");
            }
        }
        else{
            printf("Speichern fehlgeschlagen. Mit einem Upgrade auf iCloud+ erhalten Sie auf diverse Geraete mehr Speicher und zusaetzliche Funktionen, wie 'iCloud Privat-Relay', 'E-Mail Adresse verbergen' und 'HomeKit Secure Video'.\nSie koennen sogar ihr Abo mit Ihrer Familie teilen. Weitere Infos finden Sie auf apple.de/icloud");
            enter(1);
            waitForEnter("Eingabetaste zum Fortfahren druecken..");
        }
        free(Create);
    }
    else{
        printf("Speichern nicht moeglich. Mit einem Upgrade auf iCloud+ erhalten Sie auf diverse Geraete mehr Speicher und zusaetzliche Funktionen, wie 'iCloud Privat-Relay', 'E-Mail Adresse verbergen' und 'HomeKit Secure Video'.\nSie koennen sogar ihr Abo mit Ihrer Familie teilen. Weitere Infos finden Sie auf apple.de/icloud");
            enter(1);
            waitForEnter("Eingabetaste zum Fortfahren druecken..");
    }
}

重点放在 getDate 上,因为那里的值不会保存在创建数据结构(createAppointment)中。

getDate 及其其他函数:

int dayOfWeek(sDate *date){
    static int jMonth[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
    int d = date->Day;
    int m = date->Month;
    int y = date->Year;

    if(m < 3) y--;

    return(y + (y/4) - (y/100) + (y/400) + jMonth[m - 1] + d) % 7;
}


int isLeapYear(int year){
    return (((year % 4 == 0) &&  (year % 100 != 0)) || ((year % 100 == 0 && year % 400 == 0)));
}


int isDateValid(sDate *Date){
    int isDay;

    switch(Date->Month){
        case 1: isDay = 31; break;
        case 2: if(isLeapYear(Date->Year) == 1) isDay = 29; else isDay = 28; break;
        case 3: isDay = 31; break;
        case 4: isDay = 30; break;
        case 5: isDay = 31; break;
        case 6: isDay = 30; break;
        case 7: isDay = 31; break;
        case 8: isDay = 31; break;
        case 9: isDay = 30; break;
        case 10: isDay = 31; break;
        case 11: isDay = 30; break;
        case 12: isDay = 31;break;
        default: isDay = 0;
    }
    if(((Date->Day < 1) || (Date->Day > isDay) || (Date->Year < 1)) == 0){
        return 1;
    }
    else return 0;
}



int getDateFromString(char *in, sDate *dateptr){                            
    int counter = 0;                                                        
    int j = 0;                                                              
    char point = '.';                                                       
    char read[20];                                                        
                                                                            
    for(int i = 0;counter<3;i++){                                           
        if(in[i] == point || in[i] == NULL){               
            if(counter == 0) dateptr->Day = atoi(read);
            else if(counter == 1) dateptr->Month = atoi(read);
            else if(counter == 2) dateptr->Year = atoi(read);

            counter++;
            j = 0;
        }
        else{
            read[j] = in[i];
            read[j+1] = '\0';
            j++;
        }

        if(in[i] == NULL){
            if(isDateValid(dateptr)){
                dateptr->WeekDay = dayOfWeek(dateptr);
                return 1;
            }
            else return 0;
        }
    }
}



int getDate(char *prompt, sDate *date){
    char in[20];

    date = malloc(sizeof(sDate));
    
    do{
        printf(prompt);
        scanf("%s", in);
        clearBuffer();
    }while(getDateFromString(in, date) != 1); //getDateFromString is parsing 'in' which should be a date in german format(00.00.0000) into day, month and year and give the values to the 'date'-datastructure

    if(date != NULL){
        return 1;
    }
    else{
        printf("Kein Speicher vorhanden. Mit einem Upgrade auf iCloud+ erhalten Sie auf diverse Geraete mehr Speicher und zusaetzliche Funktionen, wie 'iCloud Privat-Relay', 'E-Mail Adresse verbergen' und 'HomeKit Secure Video'. Sie koennen sogar ihr Abo mit Ihrer Familie teilen. Weitere Infos finden Sie auf apple.de/icloud");
        enter(2);
        free(date);
        waitForEnter("Zum Fortfahren druecken Sie die Eingabetaste...");
        return 0;
    }
}

getDate 将在函数参数中 malloc 日期指针,并要求用户输入日期(德语格式),然后解析 getDateFromString 中的输入,给出数据结构中的值。

在调试器中观察时,我发现一切正常,并且 *date 确实具有我想要的值。但由于 *date 是一个函数参数,并且我在 createAppointment 函数中设置了 Create->Date,所以我希望它具有 *date 的值,但调试器会显示其他值。它向我显示更多的是一种随机数,而“创建”->“描述”和“创建”->“位置”都很好。

为什么会这样?

c pointers
1个回答
0
投票

您调用了

getDate("Datum: ", &(Create->Date))
并期望
getDate
函数将为
sDate
结构分配内存。让我们看一下
getDate
函数,看看为什么它不可能这样做,

int getDate(char *prompt, sDate *date){
    char in[20];
    date = malloc(sizeof(sDate));
    //some code manipulating date
}

由于

date
指针本身与 C 中的其他所有内容一样按值传递,因此调用者无法看到对其值的任何更新。在这种特殊情况下,date = malloc(sizeof(sDate))
分配一个新的内存块,并且该块的开头被分配给
date
,并且同一函数中的后续代码都使用
date
并在新块上进行操作,这就是为什么一切在函数内看起来很好。但是,一旦离开此函数,分配的块就会泄漏,您将无法再引用该块。

自从您重新分配

date

 以来,您根本就不再对 
Create->Date
 进行操作。根据经验,对函数参数的重新分配仅在 C 中具有局部效果。

在这种情况下,修复很简单。因为

Date

Create
 的成员。当您分配 
Date 时,您已经分配了
Create
所需的内存,因此只需删除行
date = malloc(sizeof(sDate));
,您将直接对
Create->Date
进行操作并获得预期的行为。

© www.soinside.com 2019 - 2024. All rights reserved.