1. 联合,通过联合可以使用不同的方式操作内存中同一段区域。
typedef union { 变量声明语句 } uni;
这里的每个变量具有排他性,计算机无法同时执行里面的变量。
typedef union
{
char c;
int i;
double j;
}
union 存储数据的开端相同,占用相同的内存,
union 的字节大小就是里面最大变量的大小,这个例子的大小为 8;
2. 计算机中存储数据有两种方式:
把低位数据存储在低地址字节中的方式叫做小端存储(小低低),反之叫大端存储。
0x12345678
假如下面四个星号代表四个字节:
* * * *
12 34 56 78 // 小端放置方式
78 56 34 12 // 大端放置方式
3. 使用枚举可以把一组数据名转换为整数,从 0 开始,以此类推;
当使用枚举后,里面的数据就可以当整数使用;
enum {SUN, TWO, WEN, MON}; // 枚举,计算机自动把 SUN 改为 0,TWO 改为 1,以此类推;
如果人为定义其中一个变量对应的数字,那么后面的以此类推,如:
enum {SUN, TWO, WEN = 7, MON}; // SUN = 0,TWO = 1,WEN = 7,MON = 8
typedef enum {SUN, TWO, WEN} week; // 枚举重命名;
week w = SUN; // 这里 w 指 SUN,也可以指代 0;
枚举和宏定义的区别:需要具体指定数字,用宏;如果仅仅是要区分每个数据,就用枚举。
4. malloc 函数可以从堆中分配制定个数的连续字节,并把首字节地址返回,如果失败,返回 NULL,也就是 0;
free 函数可以把堆中变量释放掉,需要首字节地址作为参数;
堆中变量最大区别是,这个变量由程序员自己控制;
堆中变量需要判断,其次需要销毁,具体如下:
#include <stdlib.h> // 用malloc就需要增加这个头文件
int main()
{
int *p = (int *)malloc(1 * sizeof(int)); // 给堆中分配一个4个字节的int空间,因为malloc是void型,所以要强制类型转换
if (p) // 判断malloc是否真的分配了地址,如果分配则不为零,可以执行下面的语句,这个判断很重要
{
int i = 0;
if (i = 0; i < 4; i++) // 给分配好的p输入四个整数,并输出
{
scanf("%d", p + i); // p本身就可以看作是一个数组,指数组的首地址,也可以写成 &p[i]
printf("%d\n", *(p + i)); // 也可以写成 p[i]
}
free(p); // 释放变量,此时释放的是变量值,地址还在,需要下面语句清零,否则会出现野地址
p = NULL;
}
}
5. calloc 也可以从堆中分配空间,和 malloc 的区别是:
calloc 把分配好的数据初始化为 0,malloc不可以;
其他用法一样;
int *p = (int *)calloc(4, sizeof(int)); // 这里的参数4,指分配4个整数变量,且都为0
6. realloc 调整已分配好的内存大小
if (p)
{
// p = realloc(p, 6 * sizeof(int)); 括号里的p为原分配的首地址,6为新的分配空间,这个新的空间不能直接分配给原指针p,如果直接赋值给原地址,那么,分配不成功,会导致程序失败,所以需要下面的if代码对p1进行判断,然后再赋值给p
int *p1 = NULL;
p1 = realloc(p, 6 * sizeof(int));
if (p1) // 对p1进行和上面p一样的判断
p = p1;
free(p);
p = NULL;
}
7. 二级指针变量用来记录一级指针变量的地址,声明方法:int **pp;
二级指针变量可以用来表示它自己和对应的一级指针变量以及整数变量,方法如下:
pp 表示二级指针本身地址
*pp 表示对应的一级指针地址值,相当于 &(**pp)
**pp 表示对应的整数变量值
举例:
int i = 10;
int *p = &i;
int **pp = &p;
8. 二级指针作函数的输出参数,可以让函数把内部的地址传出去
void func(**pp)
{
*pp = (int *)0x12345678; // 计算机默认把 0x12345678 当作无符号整数处理,所以要类型转换
}
int main()
{
int *p = NULL;
func(&p);
printf("%p\n", p);
}
举例:输出第一个逗号前的字符串 (erjizhizhen.c )
#include <stdlib.h> // malloc调用
void split(*p_str, **pp_str) // 前一个参数一级指针用于传入值地址,后一个二级指针用于传出值地址
{
pos = 0; // 用于计算逗号前字符个数
while ((',' != *p_str) && (0 != *p_str)) // 遇到逗号或者/0结束
{ pos++; }
pos++; // 最后多加个 1,用于存放 /0
char *p_result = NULL; // 先初始化为0,为下面的if使用
p_result = (char*)malloc(pos * sizeof(char)); // 不要和上面合为一条语句,否则if没法判断
if (p_result)
{
pos = 0; // 上面pos已经用完,这里重新初始化,下面用
while ((',' != *p_str) && (0 != *p_str))
{
*(p_result + pos) = *(p_str + pos);
pos++;
}
*(p_result + pos) = 0; // 这里pos就是指向逗号位置,所以不需要 +1
}
*pp_str = p_result; // 地址上传
}
int main()
{
char *p_str = NULL;
split("abc,def,xyz", &p_str);
printf("%s\n", p_str);
free(p_str); // 记得释放内存
p_str = NULL;
return 0;
}
9. 函数指针
int add(int i, int j){}
int sub(int i, int j){}
int main()
{
int (*p_func)(int, int) = NULL; // 声明函数指针,每个函数对应一个独立的函数指针
p_func = add; // 用函数指针之前,必须先把函数的地址记录在指针里
printf("%d\n", p_func(3, 7));
p_func = sub;
printf("%d\n", p_func(3,7));
return 0;
}
也可以用 typedef 来声明函数指针变量类型:
typedef int (*t_func)(int, int); // 定义一个函数指针类型
t_func p_func1 = NULL; // 用这个类型来声明别的函数指针变量,不用加*
10. 利用 qsort 函数可以完成一个数组中多个数据的排序问题;
需要包含 stdlib.h 头文件;
使用一个用户编写的函数来决定两个数组的前后顺序;
举例,用 qsort 把下面几个人名从小到大排序:(qsort.c)
#include <stdlib.h> // qsort调用
#include <string.h> // strcmp调用
int compare(const void* p_value1, const void* p_value2)
// 这里的两个参数形式是固定,需要传入指针类型;如果想先输出第一个参数,则 return 负数;反之返回正数;相等返回 0;
{
char **pp_str1 = (char **)p_value1; // 因为上面 *p_value 是 void 类型,所以这里要强制类型转换;
char **pp_str2 = (char **)p_value2; // 把参数重新赋值给新二级指针
return strcmp(*pp_str1, *pp_str2); // strcmp函数中,若前面参数小于后面参数,则输出 -1,和上面参数配合,即可从小到大输出
// return strcmp(*(char**)p_value1, *(char**)p_value2); 可以把上面三段代码换为这一个代码
}
int main()
{
char *strs[3] = {"wangtao", "jiangming", "liyan"}; // 指针数组,每个成员代表一个地址
qsort(strs, 3, sizeof(char *), compare);
// 第一个参数为地址变量,3指数组变量个数(或者要传入的元素个数),sizeof(char *)指每个变量大小,compare 可以随意命名
int i = 0;
for (i = 0; i < 3; i++)
printf("%s\n", *(strs + i)); // *(strs + i) 相当于 strs[i]
return 0;
}
11. 由多个指针变量构成的数组叫做指针数组,声明如下:
char *str[5];
指针数组和二级指针可以互换;
typedef union { 变量声明语句 } uni;
这里的每个变量具有排他性,计算机无法同时执行里面的变量。
typedef union
{
char c;
int i;
double j;
}
union 存储数据的开端相同,占用相同的内存,
union 的字节大小就是里面最大变量的大小,这个例子的大小为 8;
2. 计算机中存储数据有两种方式:
把低位数据存储在低地址字节中的方式叫做小端存储(小低低),反之叫大端存储。
0x12345678
假如下面四个星号代表四个字节:
* * * *
12 34 56 78 // 小端放置方式
78 56 34 12 // 大端放置方式
3. 使用枚举可以把一组数据名转换为整数,从 0 开始,以此类推;
当使用枚举后,里面的数据就可以当整数使用;
enum {SUN, TWO, WEN, MON}; // 枚举,计算机自动把 SUN 改为 0,TWO 改为 1,以此类推;
如果人为定义其中一个变量对应的数字,那么后面的以此类推,如:
enum {SUN, TWO, WEN = 7, MON}; // SUN = 0,TWO = 1,WEN = 7,MON = 8
typedef enum {SUN, TWO, WEN} week; // 枚举重命名;
week w = SUN; // 这里 w 指 SUN,也可以指代 0;
枚举和宏定义的区别:需要具体指定数字,用宏;如果仅仅是要区分每个数据,就用枚举。
4. malloc 函数可以从堆中分配制定个数的连续字节,并把首字节地址返回,如果失败,返回 NULL,也就是 0;
free 函数可以把堆中变量释放掉,需要首字节地址作为参数;
堆中变量最大区别是,这个变量由程序员自己控制;
堆中变量需要判断,其次需要销毁,具体如下:
#include <stdlib.h> // 用malloc就需要增加这个头文件
int main()
{
int *p = (int *)malloc(1 * sizeof(int)); // 给堆中分配一个4个字节的int空间,因为malloc是void型,所以要强制类型转换
if (p) // 判断malloc是否真的分配了地址,如果分配则不为零,可以执行下面的语句,这个判断很重要
{
int i = 0;
if (i = 0; i < 4; i++) // 给分配好的p输入四个整数,并输出
{
scanf("%d", p + i); // p本身就可以看作是一个数组,指数组的首地址,也可以写成 &p[i]
printf("%d\n", *(p + i)); // 也可以写成 p[i]
}
free(p); // 释放变量,此时释放的是变量值,地址还在,需要下面语句清零,否则会出现野地址
p = NULL;
}
}
5. calloc 也可以从堆中分配空间,和 malloc 的区别是:
calloc 把分配好的数据初始化为 0,malloc不可以;
其他用法一样;
int *p = (int *)calloc(4, sizeof(int)); // 这里的参数4,指分配4个整数变量,且都为0
6. realloc 调整已分配好的内存大小
if (p)
{
// p = realloc(p, 6 * sizeof(int)); 括号里的p为原分配的首地址,6为新的分配空间,这个新的空间不能直接分配给原指针p,如果直接赋值给原地址,那么,分配不成功,会导致程序失败,所以需要下面的if代码对p1进行判断,然后再赋值给p
int *p1 = NULL;
p1 = realloc(p, 6 * sizeof(int));
if (p1) // 对p1进行和上面p一样的判断
p = p1;
free(p);
p = NULL;
}
7. 二级指针变量用来记录一级指针变量的地址,声明方法:int **pp;
二级指针变量可以用来表示它自己和对应的一级指针变量以及整数变量,方法如下:
pp 表示二级指针本身地址
*pp 表示对应的一级指针地址值,相当于 &(**pp)
**pp 表示对应的整数变量值
举例:
int i = 10;
int *p = &i;
int **pp = &p;
8. 二级指针作函数的输出参数,可以让函数把内部的地址传出去
void func(**pp)
{
*pp = (int *)0x12345678; // 计算机默认把 0x12345678 当作无符号整数处理,所以要类型转换
}
int main()
{
int *p = NULL;
func(&p);
printf("%p\n", p);
}
举例:输出第一个逗号前的字符串 (erjizhizhen.c )
#include <stdlib.h> // malloc调用
void split(*p_str, **pp_str) // 前一个参数一级指针用于传入值地址,后一个二级指针用于传出值地址
{
pos = 0; // 用于计算逗号前字符个数
while ((',' != *p_str) && (0 != *p_str)) // 遇到逗号或者/0结束
{ pos++; }
pos++; // 最后多加个 1,用于存放 /0
char *p_result = NULL; // 先初始化为0,为下面的if使用
p_result = (char*)malloc(pos * sizeof(char)); // 不要和上面合为一条语句,否则if没法判断
if (p_result)
{
pos = 0; // 上面pos已经用完,这里重新初始化,下面用
while ((',' != *p_str) && (0 != *p_str))
{
*(p_result + pos) = *(p_str + pos);
pos++;
}
*(p_result + pos) = 0; // 这里pos就是指向逗号位置,所以不需要 +1
}
*pp_str = p_result; // 地址上传
}
int main()
{
char *p_str = NULL;
split("abc,def,xyz", &p_str);
printf("%s\n", p_str);
free(p_str); // 记得释放内存
p_str = NULL;
return 0;
}
9. 函数指针
int add(int i, int j){}
int sub(int i, int j){}
int main()
{
int (*p_func)(int, int) = NULL; // 声明函数指针,每个函数对应一个独立的函数指针
p_func = add; // 用函数指针之前,必须先把函数的地址记录在指针里
printf("%d\n", p_func(3, 7));
p_func = sub;
printf("%d\n", p_func(3,7));
return 0;
}
也可以用 typedef 来声明函数指针变量类型:
typedef int (*t_func)(int, int); // 定义一个函数指针类型
t_func p_func1 = NULL; // 用这个类型来声明别的函数指针变量,不用加*
10. 利用 qsort 函数可以完成一个数组中多个数据的排序问题;
需要包含 stdlib.h 头文件;
使用一个用户编写的函数来决定两个数组的前后顺序;
举例,用 qsort 把下面几个人名从小到大排序:(qsort.c)
#include <stdlib.h> // qsort调用
#include <string.h> // strcmp调用
int compare(const void* p_value1, const void* p_value2)
// 这里的两个参数形式是固定,需要传入指针类型;如果想先输出第一个参数,则 return 负数;反之返回正数;相等返回 0;
{
char **pp_str1 = (char **)p_value1; // 因为上面 *p_value 是 void 类型,所以这里要强制类型转换;
char **pp_str2 = (char **)p_value2; // 把参数重新赋值给新二级指针
return strcmp(*pp_str1, *pp_str2); // strcmp函数中,若前面参数小于后面参数,则输出 -1,和上面参数配合,即可从小到大输出
// return strcmp(*(char**)p_value1, *(char**)p_value2); 可以把上面三段代码换为这一个代码
}
int main()
{
char *strs[3] = {"wangtao", "jiangming", "liyan"}; // 指针数组,每个成员代表一个地址
qsort(strs, 3, sizeof(char *), compare);
// 第一个参数为地址变量,3指数组变量个数(或者要传入的元素个数),sizeof(char *)指每个变量大小,compare 可以随意命名
int i = 0;
for (i = 0; i < 3; i++)
printf("%s\n", *(strs + i)); // *(strs + i) 相当于 strs[i]
return 0;
}
11. 由多个指针变量构成的数组叫做指针数组,声明如下:
char *str[5];
指针数组和二级指针可以互换;