目录
五.初识指针
1.指针理解:
指针就是地址,口语中说的指针通常指的是指针变量(存放地址的变量)。
对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0),就有2的32次方个地址。每个地址标识一个字节,那我们就可以给(2^32Byte ==2^32/1024KB==2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB) 4G的空闲进行编址。在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以一个指针变量的大小就应该是4个字节。在64位机器上,一个指针变量的大小则是8个字节。
2. 指针和指针类型
指针的定义方式是: type + * 。
其实:
char* 类型的指针是为了存放 char 类型变量的地址。
short* 类型的指针是为了存放 short 类型变量的地址。
int* 类型的指针是为了存放 int 类型变量的地址。
指针类型的意义:
1.指针的类型决定了指针的步长。
2.指针的类型决定了对指针解引用的时候有多大的权限(能操作几个字节)。
比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。
3. 野指针
野指针是非法指针,成因是
1. 指针未初始化
例如:
int *p;//局部变量指针未初始化,默认为随机值
*p = 20;
return 0;
2. 指针越界访问
例如:
int arr[10] = {0};
int *p = arr;
*(p+11) = 10; //当指针指向的范围超出数组arr的范围时,p就是野指针
3. 指针指向的空间已被释放
int *p=(int *)malloc(sizeof(int));
free(p);//p是野指针,应当置空
应当规避野指针:
1. 指针初始化
2. 小心指针越界
3. 指针指向空间释放就及时置NULL
4. 避免返回局部变量的地址
5. 指针使用之前检查有效性
例如:
if(p != NULL)
{
*p = 20;
}
4. 指针运算
1.指针+- 整数(指针变量实际增加多少取决于指针的类型)
2.指针-指针(指针间运算时,指针应当指向同一块空间,指针之差绝对值是指针间的元素个数)
3.指针的关系运算(指针直接比较大小,比较的是指针变量存放的地址的大小)
注意:
标准规定: 允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。(实际在绝大部分的编译器上是可以顺利完成任务)
5. 指针和数组
数组名是首元素地址,除了sizeof(数组名)和&数组名时是指整个数组两种情况外。
*(arr+i)与arr[i]等价。
6. 二级指针
一级指针变量的地址便是二级指针,例如:
int a=10;
int *p=&a;//*表p是(一级)指针,int表指针指向的类型(整形)
int **pp=&p;//*表pp是(二级)指针,int *表指针指向的类型(整形指针)
7. 指针数组
存放指针变量的数组是指针数组。
int arr1[5];//整形数组
char arr2[6];//字符数组
int* arr3[5];//指针数组,int*表数组元素的类型(整形指针)
六.初识结构体
1.结构体类型的声明
格式:
struct tag
{
member-list;
}variable-list;
例如:
typedef struct Stu {
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}Stu;//记得分号
或者不命名,与上面声明等价。
struct {
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}Stu;//记得分号
2.结构体初始化
struct Stu //类型声明
{
char name[15];//名字
int age; //年龄
};
struct Stu s = {"zhangsan", 20};//初始化
struct Node
{
int data;
struct Point p;
struct Node* next;
}n1 = {10, {4,5}, NULL}; //结构体嵌套初始化
struct Node n2 = {20, {5, 6}, NULL};//结构体嵌套初始化
3.结构体成员访问
void print(struct Stu* ps)
{
//使用结构体变量访问指向对象的成员
printf("name = %s age = %d\n", (*ps).name, (*ps).age);
//使用结构体指针访问指向对象的成员
printf("name = %s age = %d\n", ps->name, ps->age);
}
4.结构体传参
struct S s = {{1,2,3,4}, 1000};
//结构体变量传参,需要在栈区开辟空间,不推荐
void print1(struct S s)
{
printf("%d\n", s.num);
}
//结构体地址传参,推荐
void print2(struct S* ps)
{
printf("%d\n", ps->num);
}