Unix高级编程:指针、typedef、头文件的使用

一.复习以下C语言(指针、typedef、预处理)
(一)指针
指针是地址,这句话是错误的。
"指针是地址的类型"。具体的一个地址是指针类型的。
指针类型 * 
整数类型 int
字符类型 char
数据类型:"访问内存的方式"


常量和变量,常量和变量在内存中都分配了一定的空间。
"常量"的内存空间里的值是"只读 r"的
"变量"的内存空间里的值是"可读可写 rw"的


变量四要素:名字、地址、值、数据类型


变量的内容是怎么访问到的?
通过变量的名字找到变量的地址,按照变量的类型再读取变量地址空间里的内容。
C语言本质就三句话:常量和变量,访问内存的方式,运算符的优先级
举例:代码参见 point.c
#include <stdio.h>
int main(void) {
    int a = 258; [0000 0000][0000 0000][0000 0001][0000 0010]
    char c = 'a';


    char *p1;
    p1 = (char *)&a;
    printf("*p1 = %d\n", *p1); //2 最后一个字节
    printf("*(p1+1) = %d\n", *(p1+1));//1 地址对应字节位+1,高位


    int *p2;
    p2 = (char *)&a;//gcc警告
    printf("*p2 = %d\n", *p2);//257(a原值)


    char *p3;
    p3 = (int *)&c;//gcc警告
    printf("*p3 = %d\n", *p3);//97(SCII码)


    int *p4;
    p4 = (int *)&c;
    printf("*p4 = %d\n", *p4);//一个很大的不变的数
    return 0;
}




sizeof(int) 测试int类型变量所占字节数
sizeof(char) 测试char类型变量所占字节数
char *var_p;
sizeof(var_p)  测试var_p指针在内存空间所占字节数


二级指针
int **var_q;
举例:代码参见 point2.c
#include <stdio.h>
int main(void) {
    int var_b = 321;
    int *var_p; 
    var_p = &var_b;
    int **var_q = &var_p;
    printf("var_p address %p\n", &var_p); //var_p的地址
    printf("var_q content %p\n", var_q); //var_p的地址
    printf("var_b address %p\n", &var_b); //var_b的地址
    printf("*var_q %p\n", *var_q); //var_b的地址
    printf("**var_q %d\n", **var_q); //var_b的值
    return 0;
}


补充:
数据在内存里的存放方式,分为两种:
1. 高位字节在高地址,低位字节在低地址(小端)
2. 高位字节在低地址,低位字节在高地址(大端)
在普通的计算机里,大部分采用的是小端。
在网络通讯中采用大端。


作业:写一个程序,判断使用的机器是大端还是小端?
#include <stdio.h>
int main() {
    int num = 321; //[0000 0000][0000 0000][0000 0001][0100 0001] = 321
    int *p_num = &num;
    printf("p_num address %p\n", p_num);//0x..94
    printf("p_num+1 address %p\n", p_num+1);//0x..98
    char *p_ch = (char *)&num;
    printf("*p_ch %d\n", *p_ch);//65
    printf("*(p_ch+1) %d\n", *(p_ch+1));//1
    //printf("*(p_ch-1) %d\n", *(p_ch-1));//验证高位
    if(p_num+1 > p_num && *(p_ch+1) == 1) {
        printf("此电脑为小端\n");
    }   
    else
        printf("此电脑为小端\n");
    return 0;
}






指针数组
int *arr[3]; "arr是常量"
//定义了一个数组,数组的名字是arr,数组里有3个元素,元素的类型是*类型。
字符串列表
int main(int argc, char *argv[]);


数组指针
int (*arr)[3]; "arr是一个指针类型的变量"
数据类型是 "int[3]" //12个字节
//一个  指向有3个整形数的数组  指针


一维数组
int arr[3];
定义了一个数组,这个数组的名字是arr,数组包含3个元素,元素是整数类型。
arr+1 正确
arr++ 错误(arr常量)


二维数组
int arr[2][3] = {{1,2,3},{4,5,6}};
arr 数组的名字,这个数组有2个元素,每个元素是"int[3]"类型
arr[0] 数组的名字,这个数组有3个元素,每个元素是 int 类型
arr[1] 数组的名字,这个数组有3个元素,每个元素是 int 类型
arr[1] == arr+1 == *(arr+1) ://第2个数组的首地址
arr[1][1] == *(arr[1]+1) == *(*(arr+1)+1)://第2个数组的元素5
arr[1][1] == *(*(arr + 2) - 2)://越界后指针减回来,还是元素5
int (*p)[3];
p = arr;
*(*(p + 1) + 1); //第2个数组的元素5 (p+1 等同于 p++)


函数
int *func(int, int);
这个函数的返回值是一个地址(即 int * 类型)。


函数指针(回调函数)
int (*func)(int, int);
func 是一个指针类型的变量,访问方式 int(int, int);


举例验证:指针和函数的综合运用
cp -r ../1128/tmath .
从上一层目录中靠文件夹tmath到当前目录,当前目录为一个点。
/*代码*/
#include <stdio.h>
#include "tmath.h" //昨天的头文件
int process(int(*p)(int, int), int x, int y) {
    return p(x, y); 
}
int main(void) {
    int a = 6, b = 2;
    int (*func)(int, int);
    func = add;
    printf("%d + %d = %d\n", a, b, func(a, b));
    func = sub;
    printf("%d - %d = %d\n", a, b, func(a, b));
    printf("%d + %d = %d\n", a, b, process(add, a, b));
    printf("%d - %d = %d\n", a, b, process(sub, a, b));
    printf("%d * %d = %d\n", a, b, process(mul, a, b));
    printf("%d / %d = %d\n", a, b, process(div, a, b));
    return 0;
}


指针小结:
int p; //整形变量p
int *p; //一个指向整形数的指针p
int **p; //一个指向整形数的地址的二级指针p
int *p[3]; //一个包含有3个元素的指针数组p
int (*p)[3]; //一个指向具有3个整型元素的一维数组的指针p
int *func(int, int); //一个返回整形数地址的函数func,含2整形参
int (*func)(int, int); //一个指向函数地址的函数指针func,含2整形参


(二)数据类型别名的定义
int count_t; //定义了count_t这个变量,这个变量是整形类型
typedef int count_t;
count_t是 int 类型的别名
count_t var_a;
总结类型别名三步走:
1. 定义这个类型的一个变量
2. 在第一步的基础上加上 typedef ,这时候变量的名字就是数据类型的别名
3. 使用数据类型的别名定义变量


char *point_t;
typedef char *point_t;
point_t pt; //pt是指针类型的变量,但是读取pt内容里指向的内容的时候遵守char的访问方式(相当于 char *pt)


point_t pa, pb, pc; == char *pa, *pb, *pc;


struct stu {
int num;
char name[12];
struct stu *next; //指针类型的 struct stu结构体类型
};
typedef struct stu stu_t;
stu_t st_p; //st_p 结构体类型变量
stu_t *stu_p; //stu_p 结构体类型指针变量
typedef stu_t *stu_p;
stu_p p;
struct stu *p;


int (*func)(int, int);
func是一个指针类型的变量,是这种函数的访问方式
typedef int (*func_t)(int, int);
func_t 指针的类型,访问方式是 int (int, int) 函数的访问方式
func_t p; //指针类型的变量,函数的访问方式,可以把函数地址给p
示例:
func_t arr[4] = {add, sub, mul, div};
for(int i = 0; i < 4; i++) {
    printf("%d\n", arr[i](a, b)); //替换名称,加入函数类型实参
}


int arr_t[3];
typedef int arr_t[3]; // arr_t == int[3]
arr_t st; //st是个数组,数组里面有3个元素
示例:
typedef int arr_t[3];
arr_t st = {1, 2, 3}; 
for(int i = 0; i < 3; i++) {
    printf("%d ", st[i]); //st[i] == arr_t[i] 打印结果1 2 3
}  




(三)头文件
在tmath文件夹下做改动,添加process.c文件,在该文件中实现process函数。类型的定义写在process.h头文件中。


#include <> 和 #include "" 的区别
<> //在系统指定的文件夹下找头文件
"" //在当前路径下找头文件,如果当前路径下没找到就到系统路径下找


系统指定的路径是哪些路径?怎么获取?
"-v" 在编译的时候加上该参数 //得到系统指定的多个路径

终端:#include <...> 搜索从这里开始:(下面都是路径)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姜源Jerry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值