使用指针通常可以生成更高效、更紧凑的代码
本章分成两部分内容:【基础部分】 和 【高级部分】
【基础部分】体现了指针和数组之间的密切联系,【高级部分】体现了C语言的灵活性,但也使得这部分内容不容易掌握。
掌握【基础部分】并不难,你只需牢牢记住:指针是数组名的另一种表达。
【基础部分】
5.2 指针与函数参数 【A swap 交换两个整数 】 5.3 指针与数组 【B strlen】 5.4 地址算术运算 【C strlen】 5.5 字符指针与函数 【D strcpy】 【E strcmp】 5.7 多维数组 【F 日期转换】 5.8 指针数组的初始化 【G 月份名字】 |
【高级部分】
5.6 指针数组以及指向指针的指针 【文本行排序】 5.10 命令行参数 【回显程序 echo】 【查找模式串 高级版】 5.11 指向函数的指针 【文本行排序】 5.12 复杂声明 【声明转换为文字描述】 |
5.2 指针与函数参数 【 swap 交换两个整数 】
1 2 3 4 5 6 | void swap(int *px, int *py) { int t; t = *px; *px = *py; *py = t; } |
5.3 指针与数组 【strlen】
1 2 3 4 5 6 7 8 | int strlen(char *s) { int n; for (n = 0; *s != '\0'; s++) n++; return n; } |
5.4 地址算术运算 【strlen】
1 2 3 4 5 6 7 8 | int strlen(char *s) { char *p = s; while (*p != '\0') p++; return p - s; } |
5.5 字符指针与函数
【strcpy】
数组版本
1 2 3 4 5 6 7 | void strcpy(char *s, char *t) { int i = 0; while ((s[i] = t[i]) != '\0') i++; } |
指针版本
1 2 3 4 5 6 | void strcpy(char *s, char *t) { while ((*s = *t) != '\0') { s++; t++; } } |
经验丰富的程序员写的版本:
1 2 3 4 5 | void strcpy(char *s, char *t) { while ((*s++ = *t++) != '\0') ; } |
更为精炼的版本
1 2 3 4 5 | void strcpy(char *s, char *t) { while (*s++ = *t++) ; } |
【strcmp】
字符串比较函数 strcmp(s, t)。该函数比较字符串 s 和 t,并且根据 s 按照小于、等于或大于 t 的结果分别返回负整数、0 或正整数。该返回值是 s 和 t 由前向后逐字符比较时遇到的第一个不相等字符处的字符的差值。
数组版本
1 2 3 4 5 6 7 8 9 | int strcmp(char *s, char *t) { int i = 0; for ( ; s[i] == t[i]; i++) if (s[i] == '\0') return 0; return s[i] - t[i]; } |
指针版本
1 2 3 4 5 6 7 | int strcmp(char *s, char *t) { for ( ; *s == *t ; s++, t++) if (*s == '\0') return 0; return *s - *t; } |
5.7 多维数组 【F 日期转换】
日期转换的问题,把某月某日这种日期表示形式转换为某年中第几天的表示形式,反之亦然。例如,3 月 1 日是非闰年的第 60 天,是闰年的第 61 天。
将某年某月的日期转换为某年中的第几天
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #include <stdio.h> int is_leap(int year) { if (year%400==0) return 1; if (year%100==0) return 0; if (year%4==0) return 1; return 0; } int 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 day_of_year(int year, int month, int day) { int i, leap; leap = is_leap(year); for (i = 1; i < month; i++) day = day + daytab[leap][i]; return day; } int main(int argc, char *argv[]) { int year, month, day; while (scanf("%d%d%d", &year, &month, &day)==3) { printf("%d\n",day_of_year(year, month, day) ); } return 0; } |
将某年中的第几天转换为某年某月的日期
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | void month_day(int year, int yearday, int *pmonth, int *pday) { int i, leap; leap = is_leap(year); for (i = 1; yearday > daytab[leap][i]; i++) yearday = yearday - daytab[leap][i]; *pmonth = i; *pday = yearday; } int main(int argc, char *argv[]) { int year, yearday, month, day; while (scanf("%d%d", &year, &yearday)==2) { month_day(year, yearday, &month, &day); printf("month = %d, day = %d\n", month, day); } return 0; } |
month_day 这个函数有的特别,需要计算出两个值:月份和日期;普通的函数只能返回一个值。
怎么办呢? 使用指针,传递 month 和 day 的地址。
指针:白刀子进去,红刀子出来 =》 发生了变化
5.8 指针数组的初始化 【G 月份名字】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | char* month_name(int n) { static char *name[] = { "Illegal month", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; return (n<1 || n>12) ? name[0] : name[n]; } int main(int argc, char *argv[]) { int year, yearday, month, day; while (scanf("%d%d", &year, &yearday)==2) { month_day(year, yearday, &month, &day); printf("%s %d\n", month_name(month), day); } return 0; } |
函数 month_name 返回的是什么? 月份的英文名字,是一个字符串,或者说是一个字符数组。
字符数组怎么表示? 如 char str[100] ,类型呢? char [] ,等价于 char*
1 2 3 | char* month_name(int n) 相当于 char *month_name(int n) |