目录
指针
定义:
在计算机科学中,指针(pointer)是编程语言中的一个对象,利用地址它的值直接指向
(points to)存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以
说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址
的内存单元。
内存
一个字节 0xFFFFFFFF
一个字节 0xFFFFFFFE
一个字节 0x
一个字节 ......
一个字节 0x00000002
一个字节 0x00000001
一个字节 0x00000000
int main()
{
int a = 10;
int *p = &a;//指针变量
return 0;
}
指针存变量,变量放地址,一般地说指针就是地址
32位平台上有32根地址线,2的32次方byte=4GB,即有4GB空间进行编址
指针在32位平台上是4个字节,在64位平台上是8个字节
指针和指针类型
int main(()
{
printf("%d\n",sizrof(char*));//4
printf("%d\n",sizrof(short*));//4
printf("%d\n",sizrof(intr*));//4
printf("%d\n",sizrof(double*));//4
int a = 0x11223344;
int* pa = &a;
char* pc = &b;
printf("%p\n", pa);//00DDFC20
printf("%p\n", pc); //00DDFC20
&a // 44 33 22 11
&c // 44 33 22 11
*pa = 0; //00 00 00 00 int类型可以操作4个字节
*pc = 0; //00 33 22 11 char类型只能操作1个字节
return 0;
}
总结:指针类型决定了指针进行解引用操作的时候,能够访问空间的大小
int*p: *p能够访问4个字节
char*p *p能够访问1个字节
double*p:*p能够访问8个字节
int main()
{
int a = 0x11223344;
int* pa = &s;
char* pc = &a;
printf("%p\n", pa); 0095FB58
printf("%p\n", pa+1); 0095FB5C +1变成+4个字节
printf("%p\n", pc); 0095FB58
printf("%p\n", pc+1); 0095FB59 +1就是+1个字节
return 0;
}
指针类型决定了:指针走一步走多远(指针的步长,单位是字节)
int* p:p+1 -- > 4
char* p:p+1 -- > 1
double* p+1 --> 8
int main()
{
int arr[10]={ 0 };
int* p = arr;//数组名,首元素的地址
char* p = arr;//不能实现效果,只是访问了10个字节,而数组总共有40个字节
int i = 0;
for(i =0;i < 10; i++)
{
*(p+1) = 1; //将10个元素改成1
}
return 0;
}
野指针
1.指针未被初始化
int main()
{
int a;//局部变量不初始化,默认是随机值
int *p;//局部的指针变量,就被初始化随机值
*p = 20;
return 0;
}
2.指针越界访问
int main()
{
int arr[10] = { 0 };
int *p = arr;
int i = 0;
for(i = 0; i < 12; i++)
{
p++;// 从i=10的时候,数组越界,出现野指针
}
return 0;
}
3.指针指向的内存空间被释放
int* test()
{
int a = 10;
return &a;//出函数时即销毁,int a前面加static可解决问题
}
int main()
{
int *p = test();
*p = 20;
return 0;
}
如何避免野指针
1.指针初始化
2.小心指针越界
3.指针指向空间释放即使置NULL
4.指针使用之前检查有效性
int main()
{
int b = 0;
int a = 10;
int*pa = &a;//初始化
int* p = NULL;//NULL-用来初始化指针的,给指针赋值
int a = 10;
int *pa = &a;
*pa = 20;
//
pa = NULL;
*pa = 10;//发生错误
if( pa != NULL)
{
*p = 20;
}
return 0;
}
int main()
{
int arr[10] = { 0 };
printf("%p\n", arr);//地址-首元素的地址
printf("%p\n",&arr[0]);//
printf("%p\n",&arr);//取出的是整个数组的地址
//1. &arr - &数组名-数组名不是首元素的地址-数组名表示整个数组 - &数组名 取出的是整个数组的地址
//2.sizeof(arr) - sizeof(数组名) - 数组名表示整个数组-sizeof(数组名)计算的是整个数组的大小
printf("%p\n",arr);
printf("%p\n",arr + 1);//上下相差4
printf("%p\n",&arr[0]);
printf("%p\n",&arr[0]+1);//上下相差4
printf(“%p\n”,&arr);
printf("%p\n",&arr + 1);//上下相差40
return 0;
}
int main()
{
int arr[10] = { 0 };
int* p = arr;
int i = 0;
for (i = 0; i < 10; i++)
{
*(p+i) = i;
}
//for(i = 0; i < 10; i++)
//{
// printf("%p ===== %p\n",p+i,&arr[i]);
//}
二级与多级指针
int main()
{
int a = 10;
int* pa = &a;
int** ppa = &pa;//ppa就是二级指针
int*** pppa = &ppa;//pppa就是三级指针
int****ppppa=&pppa;
printf("%d\n", **pa);//10
**ppa=20;//全部都变成20
return 0;
}
指针数组
int main(()
{
int a = 10;
int b = 20;
int c = 30;
int* pa = &a;
int* pb = &b;
int* pc = &c;
//整形数组 - 存放整形
//字符数组 - 存放字符
//指针数组 - 存放指针
int arr[10];
int* arr2[3] = {&a, &b, &c};//指针数组,存指针的数组
int i = 0;
for(i = 0; i < 3; i++)
{
printf("%d ",*(arr2[i]));
}
return 0;
}
结构体
结构体的基础知识
结构是一些值得集合,这些值称为成员变量,结构的每个成员可以是不同类型的变量。
结构的声明
struct tag
{
member-list;
}variable-list;
//如描述一个学生-一些数据
//名字
//年龄
//电话
//性别
//struct 结构体关键字 Stu - 结构体标签 struct Stu - 结构体类型
struct Stu
{
//成员变量
char name[20];
short age; int 图纸
char tele[12]; 定义结构体类型
char sex[5];
}s1,s2,s3;//s1,s2,s3 是三个全局的结构体变量 盖房子
typedef struct Stu
{
//成员变量
char name[20];//名字
short age;//年龄
char tele[12];//电话
char sex[5];//性别
char id[20];//学号
}s2;//类型(分号不能丢)
int main()
{
struct Stu s1 = {"旺财", 20, "15249287076", "保密"}; 创建结构体变量
Stu s2 = {"张三", 20 , "15249287076", "男"};//局部变量
return 0; int a = 10 房子
}
结构成员的类型
结构的成员可以是标量、数组、指针,甚至是其他结构体
结构体变量的定义和初始化
有了结构体类型,那如何定义变量,其实很简单
struct Point
{
int x;
int y;
}p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2
//初始化:定义变量的同时赋初值。
struct Point p3 = {x , y};
struct Stu //类型声明
struct S
{
int a;
char c;
char arr[20];
double d;
};
struct T
{
char ch[10];
struct S s;
char *pc;
};
int main()
{
char arr[ ] = "hello bit\n";
struct T t = {"hehe", {100, 'w', "hello world", 3.14}, arr};//结构体的嵌套
printf("%s\n", t. ch);//hehe
printf("%s\n", t. s. arr);//hello world
printf("%lf\n", t .s .d);//3.14
printf("%s\n", t .pc);//hello bit
return 0;
}
结构体的访问
typedef struct Stu
{
//成员变量
char name[20];
short age;
char tele[12];
char sex[5];
}Stu;//重命名,否则是struct Stu
void Print1(Stu tmp)
{
printf("name: %s\n", tmp.name);
printf("age: %d\n", tmp.age);
printf("tale: %s\n", tmp.tele);
printf("sex: %s\n", tmp.sex);
}
void Print2(Stu* ps)
{
printf("name: %s\n", ps->name);
printf("age: %d\n", ps->age);
printf("tale: %s\n", ps->tele);
printf("sex: %s\n", ps->sex);
}
int main()
{
Stu s = {"李四", 40, "15598886688", "男"};
//打印结构体数据
//Print1和Print2 哪个更好?
Print1(s);
Print2(&s);//用指针接收
//Print2更好,函数传参时,参数是需要压栈的。如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能的下降
//结论:结构体传参的时候,要传结构体的地址
return 0;
}
数据结构
-------线性数据结构
顺序表
链表 1->2 2->3 3->4 4->5 5->6
栈:先进后出,后进的先出
插入一个元素:压栈
删除一个元素:出栈
栈井进和栈井出
3 |
2 |
1 |
0 |
栈底
队列
------树形数据结构
二叉树
-----图