struct的成员正在被修改,但是为什么呢?

时间:2019-01-27 06:59:27

标签: c pointers struct

我一直在尝试编写解决问题的程序(例如,第19章,第10章“ C如何编程”,第八版,Deitel和Deitel),但是在识别问题时遇到了很多麻烦我遇到的问题的来源。

我一直在尝试将一些数据传递给函数“ setData”,该函数将传递的各种值分配给结构“ HealthProfile”的成员。这似乎已成功发生,并且该函数将指向struct对象的指针返回给main。然后将指针传递给函数'printStruct',这就是发生问题的地方。每次将指针传递给函数时,函数似乎都在更改存储在每个结构成员中的值,但是我不知道为什么。我不是在尝试更改成员值,将指向结构的指针传递给每个函数的目的是使函数可以访问成员中包含的值(我的实际程序具有其他函数,但是我没有之所以包含它们,是因为我仍在研究它们,再加上我所遇到的问题仅通过函数'printStruct'得以说明。

谁能告诉我我哪里出问题了?

我尝试了很多不同的方法,但是似乎没有任何效果。我怀疑问题的解决方案可能是我应该将指向函数的指针而不是指针传递给指针,但是我以这种方式修复程序没有运气。我还认为也许应该将结构成员声明为常量,但是再没有运气了。

我主要包含了一些printf语句,以说明指针的值没有改变,但是结构的成员的值在第一次调用函数'printStruct'之后(如果调用了printStruct则具有)第二次,发生分段错误。

#include <stdio.h>

typedef struct {
  char *firstName;
  char *lastName;
  char *gender;
  int birthDay, birthMonth, birthYear;
  double height, weight;
} HealthProfile;

HealthProfile * setData(char first[20], char last[20], char gender[2],
            int BirthDay, int BirthMonth, int BirthYear,
            double Height, double Weight);
void printStruct(HealthProfile * variablePtr);

int main(void)
{
  char FirstName[20], LastName[20], Gender[2];
  int age, BirthDay, BirthMonth, BirthYear, maxRate = 0, targetRate = 0;
  double bmi, Height, Weight;
  HealthProfile *variablePtr;

  puts("\n** Health Profile Creation Program **");

  printf("\n%s\n\n%s", "Enter First Name", "> ");
  scanf("%s", FirstName);

  printf("\n%s\n\n%s", "Enter Last Name", "> ");
  scanf("%s", LastName);

  printf("\n%s\n\n%s", "Enter Gender (M/F)", "> ");
  scanf("%s", Gender);

  printf("\n%s\n\n%s", "Enter date of birth (dd/mm/yyyy)", "> ");
  scanf("%d/%d/%d", &BirthDay, &BirthMonth, &BirthYear);

  printf("\n%s\n\n%s", "Enter Height (m)", "> ");
  scanf("%lf", &Height);

  printf("\n%s\n\n%s", "Enter Weight (kg)", "> ");
  scanf("%lf", &Weight);

  variablePtr = setData(FirstName, LastName, Gender, BirthDay, 
                BirthMonth, BirthYear, Height, Weight);


  printf("Address pointer: %p\n", variablePtr);
  printf("Address pointer (deref): %p\n", variablePtr->firstName);
  printf("Address pointer (deref): %p\n", variablePtr->lastName);
  printStruct(variablePtr);
  printf("Address pointer (deref): %p\n", variablePtr->firstName);
  printf("Address pointer (deref): %p\n", variablePtr->lastName);  
  /* printStruct(variablePtr); */
}

HealthProfile * setData(char first[20], char last[20], char gender[2],
            int BirthDay, int BirthMonth, int BirthYear,
            double Height, double Weight)
{
  HealthProfile profile, *profilePtr;

  profilePtr = &profile;

  profile.firstName = first;
  profile.lastName = last;
  profile.gender = gender;
  profile.birthDay = BirthDay;
  profile.birthMonth = BirthMonth;
  profile.birthYear = BirthYear;  
  profile.height = Height;
  profile.weight = Weight;  

  return profilePtr;
}

void printStruct(HealthProfile * variablePtr)
{
  printf("\n%s%s\n%s%s\n%s%s\n%s%d/%d/%d\n%s%.2lfm\n%s%.1lfkg\n",
     "First Name: ", variablePtr->firstName,
     "Last Name: ", variablePtr->lastName,
     "Gender: ", variablePtr->gender,
     "DOB: ", variablePtr->birthDay, variablePtr->birthMonth,
         variablePtr->birthYear,
     "Height: ", variablePtr->height,
     "Weight: ", variablePtr->weight);
} 

基于我编写代码的方式,我期望在打印成员值之后传递给'printStruct'的结构指针不会被更改。我想我可以多次调用该函数,而无需更改成员值,但是只需一次调用就可以更改。

2 个答案:

答案 0 :(得分:0)

这里的问题是,当函数setData返回时,您的指针指向堆栈上的地址,即“生存期”或范围结束。下一个调用的堆栈帧部分或全部覆盖了指针所指向的内存位置。这会导致随机输出,有时甚至可能是正确的输出。

要解决此问题,要么在堆中分配内存,而不是指向局部变量(malloc)的地址,要么声明局部变量im Main()并将指针传递给setData。

这两种解决方案都可以避免您遇到的问题。

答案 1 :(得分:0)

您的问题是局部变量有效的时间:

函数参数和局部变量仅在内存中存在,只要相应的函数正在执行。函数完成后,变量将变为无效,并且 可能会被其他数据覆盖。

现在让我们看一下代码的以下部分:

... setData( ... )
{
    HealthProfile profile, *profilePtr;
    profilePtr = &profile;
    ...
    return profilePtr;
}

profilePtr包含一个指向局部变量profile的指针。函数setData完成后,此变量将不再有效,并且 可能会被覆盖。

指针profilePtr(由该函数返回)将指向变量profilePtr 位于之前的内存。换句话说:指针profilePtr的值也变得无效,因为它指向一个不再存在的变量。

也许您很幸运,并且不需要内存并且该变量不会被覆盖。但是函数printf很有可能需要该内存并覆盖该变量(不再有效)。

您可以尝试以下方法:

variablePtr = setData( ... );
printf("BirthDay (first time): %d\n", variablePtr->BirthDay);
printf("BirthDay (second time): %d\n", variablePtr->BirthDay);

很有可能发生以下情况:

printf将需要profile占用的内存,因此将覆盖数据。但是,在实际调用函数BirthDay之前,将首先从结构中读取printf的值。

因此,第一个printf将打印正确的值BirthDay,而第二个printf将打印错误的值。