K&R C 5-9习题:指针实现日期转换函数遭遇编译警告与段错误
问题根因
daytab类型声明错误
原声明static char (*daytab)[13] = { ... }是指向长度为13的char数组的指针变量,本身仅占一个指针的存储空间,无法容纳两行共26个char的初始化数据,因此编译器报“标量初始化器存在多余元素”警告。正确的二维数组声明应为static char daytab[2][13] = { ... },存在连续的26字节存储空间,匹配初始化列表结构。- 指针类型不兼容
修正后的daytab作为二维数组名,退化为char (*)[13]类型(指向一维char数组的指针),直接赋值给char*类型的arr时类型不匹配,需要显式做类型转换,利用二维数组内存连续的特性,直接取首地址转为char*即可。 - 段错误来源
原错误声明下,daytab仅为一个未指向有效存储空间的野指针,按char*偏移访问时属于非法内存访问,自然触发段错误。
修复后代码
#include <stdio.h> int day_of_year(int, int, int); void month_day(int, int, int *, int *); // 修正为二维数组声明,匹配初始化列表 static char daytab[2][13] = { {0,31,28,31,30,31,30,31,31,30,31,30,31}, {0,31,29,31,30,31,30,31,31,30,31,30,31} }; int main(){ int day = day_of_year(2000,6,23); printf("%d\n", day); int pmonth, pday; // 无需用长度为1的数组,直接取变量地址传参即可 month_day(2000, 175, &pmonth, &pday); printf("%d,%d\n", pmonth, pday); return 0; } /* day of the year: set day of the year from month & day */ int day_of_year(int year, int month, int day){ int i, leap; leap = year % 4 == 0 && year % 100 != 0 || year % 400 == 0; // 显式将二维数组首地址转为char*,匹配类型 char *arr = (char *)daytab; if (leap == 1) arr += 13; // 第一行共13个char,偏移13字节刚好跳转到第二行首地址 for (i = 1; i < month; i++){ day = day + (*++arr); } return day; } /* month_day: set month and day from the day of year */ void month_day(int year, int day_year, int *pmonth, int *pday){ int i, leap; leap = year % 4 == 0 && year % 100 != 0 || year % 400 == 0; char *arr = (char *)daytab; if (leap) arr += 13; for (i = 1; day_year > *++arr; i++) day_year -= *arr; *pmonth = i; *pday = day_year; }
修复说明
- 保留了你原本的“全指针遍历、不使用数组下标”的实现逻辑,仅修正了类型声明和不兼容的指针转换问题。
- 利用二维数组内存连续的特性,直接用
char*偏移13字节即可在平年、闰年的月份表之间跳转,无需复杂的多级指针操作。 - 移除了main中冗余的长度为1的数组传参,直接用普通整型变量的地址作为输出参数,逻辑更简洁。
内容的提问来源于stack exchange,提问作者Thomas
相关产品推荐
相关产品推荐

