【问题标题】:C cannot declare valid int pointerC 不能声明有效的 int 指针
【发布时间】:2021-01-28 01:33:07
【问题描述】:

我正在开发一个程序,以将一年中的某一天与其对应的日期和月份。例如,1988 年的第 60 天对应于第 2 个月(2 月)的 29 日。

该函数使用 int 指针来分配结果月份和日期:

void month_day(int year, int yearday, int *pmonth, int *pday);

我遇到了一个奇怪的错误,得到一个分段错误错误。经过调试,我发现问题出在*pday。尽管定义了它,C 还是无法获取有效地址(它分配地址 0x0),所以在尝试分配指针地址时出现分段错误:

int main() {
int *pmonth, *pday;
month_day(1988, 60, pmonth, pday);
}

void month_day(int year, int yearday, int *pmonth, int *pday) {
  /* some calculations on yearday */
  
  /* Error takes place here because `pday` isn't a valid adress */
  *pday = yearday;
}

我已经能够通过定义 int 而不是指针并将其地址而不是指针传递给函数来克服这个问题,如下所示:

int *pmonth, pday;
month_day(1988, 60, pmonth, &pday);

不知何故,问题仅出在第二个指针上,正如我所说,这是因为指针 *pday 在其定义后被分配了一个无效地址。

但是,我真的无法解释为什么首先会发生错误。

谁能解释一下为什么会这样?

如果有必要,完整的代码在这里:

#include <stdio.h>


void month_day(int year, int yearday, int *pmonth, int *pday);

int main() {
  int *pmonth, *pday;
  month_day(1988, 60, pmonth, pday);
  printf("%d %d\n", *pmonth, *pday);
}

static char arrnonleap[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static char arrleap[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static char *daytab[] = {arrnonleap, arrleap};

/* month_day: set month, day from day of year */
void month_day(int year, int yearday, int *pmonth, int *pday) {
  int i, leap;

  if (year < 0 || yearday < 0 || yearday > 366)
    printf("Invalid year and/or yearday\n");
  
  leap = year%4 == 0 && year%100 != 0 || year%400 == 0;
  for (i = 1; yearday > (*(daytab + leap))[i]; i++)
    yearday -= (*(daytab + leap))[i];
  *pmonth = i;
  *pday = yearday;
}

【问题讨论】:

  • int *pmonth, *pday; 尚未初始化,但您取消引用它们。
  • 指针只有在指向已分配的东西时才能被取消引用......所以仅仅声明一个指针并不意味着你可以分配给它的所指对象。如果您避免使用未初始化的变量,这将很清楚:您必须为指针分配一些地址,并且您知道 NULL/0 不可用,那又如何?如您所见,您必须分配一些自动或动态分配的int 的地址。
  • ...如果你的意思是它似乎工作正常,尽管没有用另一个指针这样做,那只是意味着未定义的行为是未定义的。读取未初始化的变量是 UB,取消引用无效指针是 UB,您可以在此处同时执行这两项操作。所以你的程序什么也做不了,看起来很完美,或者炸毁了月球。这就是为什么您需要专心编写代码并始终避免使用 UB。 C 不是一种语言,编译器不会阻止你跳脚。
  • 我尝试将指针初始化为:int *pmonth=0, *pday=0;。但我仍然得到同样的错误。
  • 再读一遍我写的……要通过指针赋值,它必须指向一个对象。持有0/NULL 或任何其他任意数字的指针不会指向对象。您需要声明/分配一个真正存在的实际int 并指向它。指针只能指向某事或空无,其中“空无”表示NULL/0,如果它们指向空无,那么你如何将某事分配给空? UB 让事情变得更糟,但是在这里将未初始化的东西视为“无”,并且不要取消引用(例如通过分配)指针,直到它指向某物。

标签: c pointers declaration dereference


【解决方案1】:
int main(void) {
  int *pmonth, *pday;
  month_day(1988, 60, pmonth, pday);
  printf("%d %d\n", *pmonth, *pday);
}

您需要使用足够大的有效内存位置初始化指针以容纳int

int main(void) {
  int month,day;
  int *pmonth = &month, *pday = &day;
  month_day(1988, 60, pmonth, pday);
  printf("%d %d\n", *pmonth, *pday);
}

或者只是简单

int main(void) {
  int month, day;
  month_day(1988, 60, &month, &day);
  printf("%d %d\n", month, day);
}
int main(void) {
  int *pmonth = malloc(sizeof(*pmonth)), *pday = = malloc(sizeof(*pday));
  month_day(1988, 60, pmonth, pday);
  printf("%d %d\n", *pmonth, *pday);
  free(pmonth);
  free(pday);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-02
    • 1970-01-01
    • 1970-01-01
    • 2012-04-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多