枚举类型(enumerated type)
可以用enum可以创建一个枚举类型(enum常量是int类型, 只要能使用int型的地方就可以使用枚举类型)
其语法结构与结构的语法相同
enum spectrum {red, orange, yellow, green, blue, violet};
enum spectrum color;
color 的值可能为red、orange、yellow等, 这些符号称之为枚举符(enumerator)
int c;
color = blue;
if (color == yellow)
...;
for (color = red; color <= violet; color++)
...;
枚举变量可以是任意的整数类型
tips:c++不允许枚举变量使用++运算符, 除非将其声明为int类型。
enum常量
printf("red = %d, orange = %d\n", red, orange);
其输出:
red = 0, orange = 1
默认值
默认情况下, 枚举列表中常量都被赋予0、1、2等
enum kids (nippy, slats, skippy, nina, liz);
nippy == 0, slats == 1, skippy == 2,…
赋值
enum levels (low = 100, medium = 500, high = 2000);
enum feline {cat, lynx = 10, puma, tiger};
cat为0, lynx, puma, tiger分别为10、11、12。
用法
#include <stdio.h>
#include <string.h>
#include <stdbool.h> //c99特性
enum spectrum {red, orange, yellow, green, blue, violet };
const char* colors[] = { "red", "orange", "yellow", "green", "blue", "violet" };
#define LEN 30
int main(void)
{
char choice[LEN];
enum spectrum color;
bool color_is_found = false;
puts("Enter a color (empty line to quit):");
while (s_gets(choice, LEN) != NULL && choice[0] != '\0')
{
for (color = red; color <= violet; color++)
{
if (strcmp(choice, colors[color]) == 0)
{
color_is_found = true;
break;
}
}
if (color_is_found)
switch (color)
{
case red: puts("Roses are red.");
break;
case orange: puts("Poppies are orange.");
break;
case yellow: puts("Sunflowers are yellow.");
break;
case green: puts("Grass is green.");
break;
case blue: puts("Bluebells are blue.");
break;
case violet: puts("Violets are violet.");
break;
}
else
printf("I don not know about the color %s.\n", choice);
color_is_found = false;
puts("Next color, please (empty line to quit):");
}
puts("Good bye!");
return 0;
}
该程序使用默认值方法使之成为字符串的索引。
共享名称空间
c中在相同作用域的变量和标记的名称可以相同, 不会引起冲突
struct rect {double x; double y;};
int rect;
但是c++不允许如此, 因为其把标记名与变量名放在相同的名称空间。
typedef
其与#define 类似
但是
- typedef创建的符号名只受限于类型, 不能用于值
- typedef由编译器解释, 而非预处理器
- 比#define更灵活
假设要用BYTE表示一字节的数组, 则
typedef unsigned char BYTE;
BYTE x, y[10], *z;
作用域取决于typedef定义所在位置。
size_t, time_t类型都是由typedef定义产生的
time_t time(time_t *);
time_t在一些系统可能是unsigned long 在一些系统也可能是unsigned long long.
typedef char * STRING;
编译器会把STRING解释成一个类型的标识符, 该类型是指向char的指针
其也可作用于结构
typedef struct complex{
float real;
float imag;
} COMPLEX;
即可使用COMPLEX类型代替complex结构表示复数
使用typedef命名一个结构时, 可省略该结构的标签:
typedef struct {double x; double y;}rect;
使用方法:
rect r1 = {3.0, 6.0};
rect r2;
r2 = r1;
typedef可用于给复杂的类型命名:
typedef char (*FRPTC ()) [5];
FRPTC声明为一个函数类型, 该函数返回一个内含5个char类型元素的数组的指针。
其他复杂的声明
- 数组名后面的[]和函数名后面的()有相同优先级, 他们比解引用运算符(*)的优先级高
- [], ()都是从左到右结合
int (* uof[3])[4]; // 内含3个指针元素的数组,每个指针指向一个内含4个int类型元素的数组
char (*frump)(int); // 指向函数的指针, 该函数返回类型为char
char (* flump[3])(int); // 内含3个指针的数组, 每个指针指向返回类型为char的函数
可使用typedef建立一系列相关类型
typedef int arr5[5];
typedef arr5 *p_arr5;
typedef p_arr5 arrp10[10];
arr5 togs; //togs是内含5个int型的数组
p_arr5 p2; // p2 是一个指向数组的指针, 该数组内含5个int型值
arrp10 ap; // ap为内含10个指针的数组, 每个指针都指向一个含5个int型值的数组
函数和指针
指向函数的指针中储存着函数代码起始处的地址。
声明函数指针时必须声明指针指向的函数类型, 为指明函数类型, 要指明函数签名, 即函数的返回类型与形参类型
void (*pf)(char *); //pf是一个指向函数的指针
定义方法:
void ToUpper(char *);
void ToLower(char *);
int round(double);
void (*pf)(char *);
pf = ToUpper;
pf = ToLower;
pf = round;
pf = ToLower(); //无效, ToLower()不是地址
访问方法:
void ToUpper(char *);
void ToLower(char *);
void (*pf) (char *);
char mis[] = "Nina Metier";
pf = ToUpper;
(*pf)(mis); //语法1
pf = ToLower;
pf(mis); //语法2
void show(void (* fp)(char *), char * str);
其声明了两个形参, fp是一个函数指针, str是一个数据指针; fp指向的函数接受char * 类型参数, 返回类型为void。
可以这样调用函数:
show(ToLower, mis); // show使用ToLower()函数
show(pf, mis); //show使用pf指向的函数
show()使用方法;
void show(void (* fp)(char *), char * str)
{
(*fp)(str); //所选函数作用于str
puts(str); //显示结果
}
带返回值的函数作为参数传递给其他函数有两种方法;
function1(sqrt); //传递sqrt()函数地址, 在function1中使用该函数
function2(sqrt(4.0)); //传递sqrt()函数返回值
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define LEN 81
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*); // 声明函数指针
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()函数拷贝一份
show(pfun, copy);
}
puts("Enter a string (empty to quit):");
}
puts("bye!");
return 0;
}
char showmenu(void)
{
char ans;
puts("Enter menu choice:");
puts("u) uppercase 1) 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(ans);
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);
puts(str);
}
程序通过将不同的函数赋予函数指针, 但是也可以把这四个函数中任一函数名作为参数, 如
show(Transpose, copy);
可以使用typeddef:
typedef void (* V_FP_CHARP)(char *);
void show (V_FP_CHARP fp, char *);
V_FP_CHARP pfun;
可以声明并初始化一个函数指针数组:
v_FP_CHARP arpf[4] = {ToUpper, ToLower, Transpose, Dummy};
把showmenu()返回值改为int, 若用户输入u, 则返回0, 若输入l, 则返回1, 以此类推
index = showmenu();
while(index >= 0 && index <= 3)
{
strcpy(cpoy, line);
show (arpf[index], copy);
index = showmenu();
}