1 指针
首先看变量在内存中的存储
有时候需要获取并使用程序运行中某个变量的内存地址,如何获取这个地址、如何存储这个地址?
&取地址符,&a就是获得了a的地址
可以存储地址的变量称为指针变量。
指针看起来就是地址,但不仅仅是地址信息,还包含类型信息
2 指针变量的声明和初始化
声明指针变量
1
2int *pn; //pn 是整型指针,指向整型变量
指针变量名是pn,不是*pn * 是指针声明符
1
2
3float *pa; //pa 是浮点型指针,指向浮点型变量 char *pc; //pc 是字符型指针,指向字符型变量
声明并初始化指针变量
1
2int i, *p = &i;
等价于
1
2
3int i; int *p = &i;
等价于
1
2
3int i, *p; p = &i;
下面看指针和变量在内存中的形式
最好在声明指针时就对它进行初始化。一个指向不确定的指针是很危险的,因为通过指针可以访问其指向的内存区域,会造成意外覆盖内存
如果声明指针变量时不能确定它的指向,可以初始化为NULL
1
2int *p = NULL;
值为NULL的指针称为空指针,这意味着,指针并不指向任何地址。在头文件 stdio.h 中,NULL 定义为常量0。
3 指针与数据类型
前面关于指针的讨论忽略了一个重要事实,即不同类型的数据在内存中占用的字节数量是不同的。 而指针仅指示了第一个字节的地址。如何通过指针访问该数据:读取多少个字节? 如何理解这些字节内容?
所以编译器必须知道它所指向的数据类型,每个指针都和某个数据类型相关联。
1
2
3int *p; //p指向一个int类型的对象 ,读4个字节 double *p; //p指向double类型的对象,读8个字节
(1)指针变量也是一个变量,只不过该变量中存储的是另一个对象的内存地址
(2)如果一个变量存储另一个对象的地址,则称该变量指向这个对象
(3)由于指针值是数据,指针变量可以赋值,所以一个指针的指向在程序执行中可以改变。指针p 在执行中某时刻指向变量a,在另一时刻也可以指向变量b
1
2
3int a; int *p = &a; // p中存的是a的地址

4 间接访问运算符
直接访问n:通过变量名访问,如 n = 15;
间接访问n:通过另一个变量来访问,pn中存储了n的地址,通过pn可以间接访问n,*pn就是对n的引用
1
2
3
4
5
6
7
8
9
10
11
12int a = 3, *p = NULL; printf("a的地址:%pn", &a); //用格式符%p以十六进制格式输出内存地址。 printf("a的值:%dn", a); p = &a; //让指针变量p指向a printf("np的地址:%pn", &p); //变量p也需系统分配内存地址,也有内存地址 printf("p的值:%pn", p); printf("*p的值:%dn", *p); *p=10; //等价于a=10; printf("na=%d, *p=%dn", a, *p); //指针变量p指向a, *p是通过a的地址间接访问a

1
2
3
4
5
6
7
8
9
10#include<stdio.h> int main() { int a = 1, x, y, *p; p = &a; x = (*p)++; //即x=a++; 先使用再增1,即x=a; a++; y=*p; printf("x=%d,y=%dn",x,y); //x=1,y=2 }
x = (* p)++;
++运算的对象是* p,而不是p
++后置,先使用再增值,
等价于:
x=* p; (*p)++;
将 p 所指向的变量值加1
5 指针作为函数的参数
有了指针的概念,重新思考以下问题:如何在被调函数中改变主调函数的局部变量?
C语言中,参数传递是“传值”方式,形参是实参的副本,因而在被调函数中,对形参的修改不影响实参变量的值。
为达到改变变量的目的,需用指针变量作为函数的形参,将实参变量的指针传给形参。此时,在函数执行过程中,通过形参指针,间接访问被调函数中的变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14//以下程序不能实现a、b值的互换 void swap(int x, int y) { int t; t = x; x = y; y = t; } int main() { int a = 3, b = 5; swap( a, b ); printf("%d %dn",a,b); // 3 ,5 return 0; }

形参变量值的改变不会影响实参可以打个比方,main用传真方式把a和b的内容传给了swap,swap接到传真,打印到x和y上,x和y是a和b的副本,x和y的改变不会影响a和b的内容。
试试看:用指针解决问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14void swap( int *pa, int *pb) { int t; t = *pa; *pa = *pb; *pb=t; //*pa是对a的引用,*pb是对b的引用 } int main() { int a = 3, b = 5; swap(&a, &b); // 传递a,b的地址 printf("%d %dn",a,b); // 5 3 return 0; }

通过形参指针变量pa和pb间接访问并改变了a和b的值打个比方,是main给swap打电话,告诉他a和b这两个原件就在档案柜的第315(存入pa)、316号抽屉(存入pb) ,swap直接去315和316号抽屉,直接访问和修改的是原件a和b
试试看:为何不能实现互换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include<stdio.h> void swap( int *pa, int *pb) { int *t; t = pa; pa = pb; pb = t; } int main() { int a = 3, b = 5; swap(&a, &b); printf("%d %dn", a, b); // 3 5 return 0; }

函数调用结束时,pa,pb被释放, 形参指针变量值的改变不会影响实参
如何访问主调函数中的变量,要通过函数调用来改变主调函数中某个变量的值:
(1) 在主调函数中,将该变量的地址或者指向该变量的指针作为实参
(2) 在被调函数中,用指针类型形参接受该变量的指针
(3) 在被调函数中,用形参指针间接访问主调函数中的变量。
6 结构类型的定义方法
1
2
3
4
5
6
7
8struct 结构体名 { 数据类型 成员1名; 数据类型 成员2名; …. 数据类型 成员n名; }; //;不要漏掉

结构类型变量的定义
常用两种方法:
1 先定义结构体模板,再定义变量名
1
2
3
4
5
6
7
8
9
10struct student { long stuID; char stuName[10]; char stuSex; char birthYear; int mathScore; }; struct student stu1; // stu1是变量
2 在定义类型的同时定义变量
1
2
3
4
5
6
7
8
9struct student { long stuID; char stuName[10]; char stuSex; char birthYear; int mathScore; }stu1;
7 嵌套的结构类型
在一个结构体内其成员可以是另一个结构体
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17struct date { int year; int month; int day; }; struct student { long studentID; char stuName[10]; char stuSex; struct date birthday; int mathScore; }; struct student stu1;
注意:不可以嵌套同类型的结构体
8 使用typedef定义数据类型别名
可以这样写
1
2
3
4
5
6
7
8
9struct student { long stuID; char stuName[10]; char stuSex; int mathScore; }; typedef struct student STUDENT;
也可以
1
2
3
4
5
6
7
8typedef struct student { long stuID; char stuName[10]; char stuSex; int mathScore; } STUDENT;
定义后别名和原名通用
1
2
3struct student stu1; STUDENT stu2;
9 结构变量的初始化
不嵌套情况
1
2
3STUDENT stu2={100010,"King哥",'M',95}; struct student stu1={100010,"King哥",'M', 95};
嵌套情形
1
2STUDENT stu1={100010,"King哥",'M', {2001,7,9}, 95};
10 结构变量成员的引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15typedef struct date { int year; int month; int day; }DATE; struct student { long stuID; char stuName[10]; char stuSex; DATE birthday; int mathScore; } stu1;
圆点运算符
结构体变量名.成员名
1
2stu1.stuID = 100012;
嵌套情形
以级联方式逐级访问
1
2stu1.birthday.year = 1990;
11 结构数组
结构数组定义
元素为结构类型的数组称为结构数组。
在实际应用中,经常用结构数组来表示具有相同数据结构的一个群体。例如一个班的学员档案,一个公司的职工档案等
1
2
3
4
5
6
7
8struct student { int num; char name[20]; char sex; float score; }stu[30];
定义了一个结构数组stu,共有30个元素,stu[0]~stu[29]。每个数组元素都具有struct student的结构形式
结构数组元素的成员引用
结构体数组名[下标] . 结构体成员名
使用方法与同类型的变量完全相同
1
2
3
4stu[5].num = 26; strcpy(stu[5].name, "Zhang San"); stu[4] =stu[1];
12 结构指针
结构指针:指向结构类型变量的指针
结构类型名 *指针变量名
1
2
3
4struct student stu1 = { 1,"СÃ÷",'F',45}; struct student *p; p = &stu1;
12 通过结构指针访问结构成员
(1) 用* p访问结构成员
1
2(*p).num = 36;
(2) 用指向运算符“->”访问结构成员。
1
2p->num = 36;
当p = &stu1时,以下三条语句相同:
1
2
3
4
5p = &stu1; stu1.num = 36; (*p).num = 36; p->num = 36;
结构成员的多种访问方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include<iostream> #include<bits/stdc++.h> using namespace std; struct employee { char name[20]; int age; int tel; }; int main( ) { struct employee emp1 = {"jk", 22, 67896544}; struct employee *p; p = &emp1; printf("%s,%d,%dn", emp1.name, emp1.age, emp1.tel); printf("%s,%d,%dn", (*p).name, (*p).age, (*p).tel); printf("%s,%d,%dn", p->name, p->age, p->tel); return 0; }
13 内存分配函数
malloc()——分配内存块,但不对内存块初始化。
calloc()——分配内存块,且对内存块清零。
realloc()——调整先前分配的内存块的大小。
函数返回void *类型的值。void *类型的指针是”通用”指针,本质上只是内存地址。(由于无法知道计划存储在内存块中的数据是什么类型,所以它们不能返回int类型、char类型等普通类型的指针。)
如果内存分配失败返回“空指针”,用宏名”NULL”表示。空指针是“不指向任何地方的指针”
1 动态存储分配函数malloc()
void *malloc(unsigned size)
在内存的动态存储区中分配一连续空间,其长度为size
若申请成功,则返回一个指向所分配内存空间的起始地址的指针
若申请内存空间不成功,则返回NULL(值为0)
返回值类型:(void *)
通用指针的一个重要用途 :将malloc的返回值转换到特定指针类型,赋给一个指针
2 动态存储释放函数free
void free(void *ptr)
释放由动态存储分配函数申请到的整块内存空间,ptr为指向要释放空间的首地址。
当某个动态分配的存储块不再用时,要及时将它释放
3 其它动态存储分配函数
void calloc(unsigned n, unsigned size)
calloc函数为n个元素的数组分配内存,其中,每个元素长度都是size个字节。(calloc与malloc类似,但是主要的区别是存储在已分配的内存空间中的值默认为0,使用malloc时,已分配的内存中可以是任意的值。)
void * realloc(void ptr, unsigned size)
调整先前分配的内存块的大小, ptr指向原先通过malloc、calloc或realloc获得的内存块,size是内存块的新尺寸
1
2
3
4p = (int *) malloc (n* sizeof(int)); p = (int *) calloc (n, sizeof(int)); p = (int *) realloc (p, n*sizeof(int));
最后
以上就是激情荔枝最近收集整理的关于数据结构-指针和结构体的全部内容,更多相关数据结构-指针和结构体内容请搜索靠谱客的其他文章。
发表评论 取消回复