指针数组和数组指针:
int a[8][8]; //一个内含int数组的数组
int ** ptr;//指向指针的指针,被指向的指针指向int
int * b[10];//指针数组,内含10个元素的数组,每个元素都是指向int类型的指针
int (* b)[10];//数组指针,一个指向数组的指针,该数组有10个int类型的值
int * c[3][4];//二维指针数组,每个元素都是指向int类型的指针
int (* d)[3][4];//一个指向二维数组的指针,该数组中含int类型值
int (* d[3])[4];//一个内含三个指针元素的数组,每个指针都指向一个内含4个int类型元素的数组。
要看懂上述声明,关键要理解 * 、()、和 [ ] 的优先级:
- ()和 [ ] 的优先级相同,但比 * (解引用运算符)的优先级高。
- 遵循从左往右结合。
指针函数和函数指针:
char * a(int); //指针函数,首先是一个函数,返回值为char类型的指针
char (* b) (int); //函数指针,首先是个指针,它指向函数,该函数的返回类型为char
char (* c[3])(int);//内含三个指针的数组,每个指针都指向一个返回值为char类型的函数。
函数指针
通常,函数指针用作另一个函数的参数,告诉函数要使用哪一个函数。
函数指针:指向函数的指针。函数也有地址,因为函数的机器语言实现由载入内存的代码组成,指向函数的指针存储着函数代码的起始位置的地址。
函数原型:
void ToUpper(char *);//带char * 类型参数、返回类型是void的函数
指向该函数的指针:
void (*pf) (char *); //pf是指向函数的指针
把函数名ToUpper替换成表达式(pf)是创建指向函数指针最简单的方式。所以 想声明一个指向某类型函数的指针,可以先写出该函数的原型,然后再把函数名用(*pf)替换即可 。
声明了函数指针后,可以把类型匹配的函数地址赋给它,在这种上下文中,函数名可以用于表示函数的地址:
void ToUpper(char *);
void ToLower(char *);
int round(double);
void (*pf)(char *);
pf = ToUpper; //有效,ToUpper是该类型函数的地址
pf = ToLower; //有效,ToLower是该类型函数的地址
pf = round; //无效,round不是该类型函数的地址
pf = ToLower(); //无效,ToLower()不是地址
//函数指针
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#define LEN 81
char * s_gets(char * st, int n);
char showmenu(void);
void eatline(void); //读取至行末尾
void show(void(*fp)(char *), char * str);
void ToUpper(char *);
void ToLower(char *);
void Transpose(char *);
void Dummy(char *);
int main(void)
{
char line[LEN];
char copy[LEN];
char choice;
void(*pfun)(char *);//声明一个函数指针,被指向的函数接受 char * 类型的参数,无返回值。
puts("Enter a string (empty line to quit):");
while(s_gets(line,LEN) != NULL && line[0] != '\0')
{
while ((choice = showmenu()) != 'n')
{
switch(choice)
{
case 'u': pfun = ToUpper; break;
case 'l': pfun = ToLower; break;
case 't': pfun = Transpose; break;
case 'o': pfun = Dummy; break;
}
strcpy(copy,line);
show(pfun, copy);
}
puts("Enter a string (empty line to quit):");
}
puts("Bye!");
return 0;
}
char showmenu(void)
{
char ans;
puts("Enter menu choice:");
puts("u) uppercase l) lowercase");
puts("t) transposed case o) original case");
puts("n) next string");
ans = getchar();
ans = tolower(ans);
eatline(); //清理输入行
while (strchr("ulton", ans) == NULL)
{
puts("Please enter a u, l, t, o, or n:");
ans = tolower(getchar());
eatline();
}
return ans;
}
void eatline(void)
{
while (getchar() != '\n')
continue;
}
void ToUpper(char * str)
{
while (*str)
{
*str = toupper(*str);
str++;
}
}
void ToLower(char * str)
{
while (*str)
{
*str = tolower(*str);
str++;
}
}
void Transpose(char * str)
{
while(*str)
{
if(islower(*str))
*str = toupper(*str);
else if(isupper(*str))
*str = tolower(*str);
str++;
}
}
void Dummy(char * str)
{
//不改变字符
}
void show(void(*fp) (char *), char * str)
{
(*fp)(str);//把用户选定的函数作用于str
puts(str);//显示结果
}
char * s_gets(char * st, int n){
char * ret_val;
int i = 0;
ret_val = fgets(st, n, stdin);//如果一切进行顺利,返回的是第一个字符的地址 ,遇到文件结尾或者错误时返回NULL
if(ret_val){//如果输入成功
while (st[i] != '\n' && st[i] != '\0')//跳转到字符串末尾
i++;
if(st[i] == '\n')//替换掉换行符
st[i] = '\0';
else//如果输入字符串超出字数,之后的字符就省略
while (getchar() != '\n')
continue;
}
return ret_val;//输入正常则返回字符串首字符地址
}