C学习笔记(5)--- 指针第二部分,字符串,结构体。
1. 函数指针(function pointer):
函数指针是指向函数的指针变量。
通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。
函数指针可以像一般函数一样,用于调用函数、传递参数。
函数指针变量的声明:
typedef int (*fun_ptr)(int,int);
例子:
sub:指针函数是返回指针的函数,详见我上一篇文章。
2.回调函数(callback function):
函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的函数。
"
以下是来自知乎作者常溪玲的解说:
你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。
"
意思简单来说就是:你现在定义的a函数的参数包含了一个你现在还不知道的b函数,所以你在参数中做了一个b函数指针以便引用这个b函数。 一旦引用的这个b函数被定义了,你就可以在runtime使用你的a函数。
例子:
sub:size_t 是一种数据类型,近似于无符号整型,但容量范围一般大于 int 和 unsigned。这里使用 size_t 是为了保证 arraysize 变量能够有足够大的容量来储存可能大的数组.
3.字符串(string):
在 c 语言中,字符串实际上是使用 null 字符 '\0' 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。
下面的声明和初始化创建了一个 "hello" 字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 "hello" 的字符数多一个。
char greeting[6] = {'h', 'e', 'l', 'l', 'o', '\0'}; (一般正常人不会用这种)(不需要把 null 字符放在字符串常量的末尾。c 编译器会在初始化数组时,自动把 '\0' 放在字符串的末尾。)
char greeting[] = "hello"; (比较通用,和其他语言很像,注意“[ ]”,因为c里面string是char的array。)
常见操作:
strcpy(s1, s2); 复制字符串 s2 到字符串 s1。
strcat(s1, s2); 连接字符串 s2。
strlen(s1); 返回字符串 s1 的长度。
strcmp(s1, s2); 如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回小于 0;如果 s1>s2 则返回大于 0。
strchr(s1, ch); 返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。
strstr(s1, s2); 返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。
sub:
strlen 与 sizeof的区别:
strlen 是函数,sizeof 是运算操作符,二者得到的结果类型为 size_t,即 unsigned int 类型。
sizeof 计算的是变量的大小,不受字符 \0 影响;
而 strlen 计算的是字符串的长度,以 \0 作为长度判定依据。
4.结构体(struct):
a.定义:
c 数组允许定义可存储相同类型数据项的变量,结构是 c 编程中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。
假设我们有一个电子图书馆,我们可以用结构体来定义一本书及其属性: 1.标题 2.作者。。。之类。
为了定义结构,您必须使用 struct 语句。struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下:
struct books {
char title[50];
char author[50];
char subject[100];
int book_id;
}book;
在一般情况下,tag 、member-list、variable-list 这 3 部分(对应代码里面的books, char title[50]; , book)至少要出现 2 个。
sub :
1.不同的定义方式产生的结构体可以被视为不同的类型,无法相等(不管成员是不是一样).
2.结构体的成员可以包含其他结构体,也可以包含指向自己结构体类型的指针,而通常这种指针的应用是为了实现一些更高级的数据结构如链表和树等。
3.可以在定义的时候初始化,跟变量一样。
详见:
b. 结构访问还有使用:
为了访问结构的成员,我们使用成员访问运算符(.)。成员访问运算符是结构变量名称和我们要访问的结构成员之间的一个句号。您可以使用 struct 关键字来定义结构类型的变量。
比如 你要访问 book1 的title --- book1.title (如果学过面对对象编程的朋友估计感觉很眼熟)
c.结构作为函数参数:
您可以把结构作为函数参数,传参方式与其他类型的变量或指针类似。您可以使用上面实例中的方式来访问结构变量:
void printbook( struct books book ){
。。。
。。。
。。。
}
d.指向结构的指针:
struct books *struct_pointer; 定义
struct_pointer = &book1; 结构变量的地址
struct_pointer->title; 指向该结构的指针访问结构的成员
e.位域:
有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有 0 和 1 两种状态,用 1 位二进位即可。为了节省存储空间,并使处理简便,c 语言又提供了一种数据结构,称为"位域"或"位段"。
所谓"位域"是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。
位域和结构体的定义基本上差不多,只不过需要多加 位域长度 。
struct bs{
int a:8;
int b:2;
int c:6;
}data;
说明 data 为 bs 变量,共占两个字节。其中位域 a 占 8 位,位域 b 占 2 位,位域 c 占 6 位。
使用时这两种都可以:1. data.a 2. data->a
sub:
1.一个位域存储在同一个字节中,如一个字节所剩空间不够存放另一位域时,则会从下一单元起存放该位域。也可以有意使某位域从下一单元开始。
2.由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。如果最大长度大于计算机的整数字长,一些编译器可能会允许域的内存重叠,另外一些编译器可能会把大于一个域的部分存储在下一个字中。
3.位域可以是无名位域,这时它只用来作填充或调整位置。无名的位域是不能使用的.
4.位域在本质上就是一种结构类型,不过其成员是按二进位分配的。
5.结构体变量的首地址能够被其最宽基本类型成员的大小所整除。
6.结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding)。即结构体成员的末地址减去结构体首地址(第一个结构体成员的首地址)得到的偏移量都要是对应成员大小的整数倍。
引用:
上一篇: 了解青团保质期,学会如何保存青团