【发布时间】: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