C语言中结构体的高级应用与操作技巧
立即解锁
发布时间: 2025-08-22 00:15:36 阅读量: 2 订阅数: 4 


C语言编程精髓与实践指南
### C语言中结构体的高级应用与操作技巧
#### 1. 结构体指针的使用
在C语言里,结构体指针是极为常用的。比如以下代码:
```c
pp = &origin;
printf("origin is (%d,%d)\n", (*pp).x, (*pp).y);
```
这里`(*pp).x`的括号是必需的,因为结构体成员运算符`.`的优先级高于`*`。表达式`*pp.x`实际意味着`*(pp.x)`,这是非法的,因为`x`并非指针。
为了简化操作,C语言提供了一种简写方式。若`p`是指向结构体的指针,那么`p->member-of-structure`就可用于引用特定成员。所以上述代码也能写成:
```c
printf("origin is (%d,%d)\n", pp->x, pp->y);
```
`.`和`->`运算符都是从左至右结合的。例如有如下定义:
```c
struct rect r, *rp = &r;
```
那么下面四个表达式是等价的:
- `r.pt1.x`
- `rp->pt1.x`
- `(r.pt1).x`
- `(rp->pt1).x`
结构体运算符`.`和`->`,以及用于函数调用的`()`和用于下标的`[]`,处于优先级层次的顶端,结合性很强。例如:
```c
struct {
int len;
char *str;
} *p;
```
对于`++p->len`,它会使`len`的值增加,而非`p`,因为隐含的括号是`++(p->len)`。可以使用括号来改变结合性:`(++p)->len`会先增加`p`的值,再访问`len`;`(p++)->len`则是先访问`len`,再增加`p`的值(最后一组括号并非必需)。
同理,`*p->str`会获取`str`所指向的内容;`*p->str++`会先访问`str`所指向的内容,再增加`str`的值;`(*p->str)++`会增加`str`所指向内容的值;`*p++->str`会先访问`str`所指向的内容,再增加`p`的值。
#### 2. 结构体数组的应用
假设要编写一个程序来统计每个C关键字的出现次数。一种方法是使用两个并行数组:
```c
char *keyword[NKEYS];
int keycount[NKEYS];
```
不过,并行数组的使用暗示了另一种组织方式——结构体数组。每个关键字可看作一个对:
```c
char *word;
int count;
```
并且存在一个这样的对的数组。结构体声明如下:
```c
struct key {
char *word;
int count;
} keytab[NKEYS];
```
这声明了一个结构体类型`key`,定义了一个该类型的结构体数组`keytab`,并为其分配了存储空间。数组的每个元素都是一个结构体,也可写成:
```c
struct key {
char *word;
int count;
};
struct key keytab[NKEYS];
```
由于`keytab`结构体包含一组常量名称,将其设为外部变量并在定义时一次性初始化是最为简便的。结构体初始化类似于之前的操作,定义后紧跟一个用花括号括起来的初始化列表:
```c
struct key {
char *word;
int count;
} keytab[] = {
"auto", 0,
"break", 0,
"case", 0,
"char", 0,
"const", 0,
"continue", 0,
"default", 0,
/* ... */
"unsigned", 0,
"void", 0,
"volatile", 0,
"while", 0
};
```
初始化列表是成对列出的,对应结构体的成员。更精确的做法是用花括号将每个“行”或结构体的初始化列表括起来,不过当初始化列表为简单变量或字符串,且所有成员都存在时,内部花括号并非必需。若提供了初始化列表且`[]`为空,数组`keytab`的元素数量会自动计算。
关键字计数程序从`keytab`的定义开始。主程序通过反复调用`getword`函数来读取输入,每次获取一个单词。每个单词会在`keytab`中使用二分查找函数进行查找,关键字列表必须按升序排列。以下是完整代码:
```c
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define MAXWORD 100
int getword(char *, int);
int binsearch(char *, struct key *, int);
/* count C keywords */
main()
{
int n;
char word[MAXWORD];
while (getword(word, MAXWORD) != EOF)
if (isalpha(word[0]))
if ((n = binsearch(word, keytab, NKEYS)) >= 0)
keytab[n].count++;
for (n = 0; n < NKEYS; n++)
if (keytab[n].count > 0)
printf("%4d %s\n",
keytab[n].count, keytab[n].word);
return 0;
}
/* binsearch: find word in tab[0]...tab[n-1] */
int binsearch(char *word, struct key tab[], int n)
{
int cond;
int low, high, mid;
low = 0;
high = n - 1;
while (low <= high) {
mid = (low+high) / 2;
if ((cond = strcmp(word, tab[mid].word)) < 0)
high = mid - 1;
else if (cond > 0)
low = mid + 1;
else
return mid;
}
return -1;
}
```
`NKEYS`表示`keytab`中关键字的数量。虽然可以手动计数,但使用机器计算会更简便、安全,特别是在列表可能发生变化的情况下。一种方法是用空指针结束初始化列表,然后遍历`keytab`直到找到末尾。不过,由于数组大小在编译时就已确定,可使用`sizeof`运算符来计算元素数量。`sizeof`运算符可用于计算任何对象的大小,表达式`sizeof object`和`sizeof (type name)`会返回指定对象或类型的字节数。在本例中,关键字的数量可通过数组大小除以单个元素的大小来计算,可使用以下`#define`语句设置`NKEYS`的值:
```c
#define NKEYS (sizeof keytab / sizeof(struct key))
```
也可写成:
```c
#define NKEYS (sizeof keytab / sizeof(keytab[0]))
```
这种写法的优点是,即使类型发生变化,也无需修改代码。需要注意的是,`sizeof`不能用于`#if`行,因为预处理器不会解析类型名称,但`#define`中的表达式不会由预处理器求值,所以此处代码是合法的。
`getword`函数用于从输入中获取下一个“单词”,单词可以是以字母开头的字母和数字字符串,也可以是单个非空白字符。函数返回值为单词的第一个字符,若到达文件末尾则返回`EOF`,若字符不是字母则返回该字符本身。代码如下:
```c
/* getword: get next word or character from input */
int getword(char *word, int lim)
{
int c, getch(void);
void ungetch(int);
char *w = word;
while (isspace(c = getch()))
;
if (c != EOF)
*w++ = c;
if (!isalpha(c)) {
*w = '\0';
return c;
}
for ( ; --lim > 0; w++)
if (!isalnum(*w = getch())) {
ungetch(*w);
break;
}
*w = '\0';
return word[0];
}
```
`getword`函数使用了之前编写的`getch`和`ung
0
0
复制全文
相关推荐










