博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数据结构——学习线性表的预备知识
阅读量:3956 次
发布时间:2019-05-24

本文共 5338 字,大约阅读时间需要 17 分钟。

文章目录

一. 指针

1.引例

# include 
int main(void){
int * p; int i = 10; int j; p = &i; //p指向i第一个字节地址 j = *p; return 0;}

在这里插入图片描述

int * 表示该p变量只能存储int类型变量地址如果p里面没有保存一个变量地址,那么p里面就是垃圾值(也就是野指针)那么*p是一个垃圾值、不确定的值,系统一般不允许你访问i==*p,但是修改p变量里面的值和修改i变量里面的值都互补影响。

2. 指针的重要性

指针是C语言的灵魂

3. 指针的定义

  • 指针就是地址,地址就是指针
  • 指针变量是存放内存单元地址的变量
  • 指针的本质是一个操作受限的非负整数

(1). 内存的基本概念

  1. 内存是用来存储数据的设备,它的存储速度介于寄存器和硬盘之间
  2. 内存是CPU唯一可以访问的大容量的存储设备,所有的硬件中的程序和数据必须调入内存之后方可被CPU执行!切记:CPU不能直接处理硬盘中的数据
  3. 内存的问题是软件开发中最核心的问题之一,如:内存的分配,内存的释放,内存什么时候分配,内存什么时候释放,由谁来分配,由谁释放,分配是在什么地方,访问权限如何?
  4. 内存是多字节组成的线性一维存储空间
  5. 内存的基本划分单位是字节
  6. 每个字节含有8位,每一位存放1个0或1个1
  7. 字节和编号是一一对应的,每个字节都有一个唯一确定的编号,一个编号对应一个字节!这个编号也叫地址
  8. 一个系统所能管理的内存空间的大小取决于参与编号的二进制位数

地址:内存单元编号

从0开始的非负整数范围:0-FFFFFFFF(0-4G-1)内存大小:表示有多少个单元* 每个单元格的大小 (2^32 * 1Byte)

(2). 软件运行与内存关系(垃圾数据)

内存是在操作系统的统一管理下使用的!

  1. 软件在运行前需要向操作系统申请存储空间,在内存空闲空间足够时,操作系统将分配一段内存空间并将外存中软件一份存入该内存空间中,并启动该软件的运行
  2. 在软件运行期间,该软件所占内存空间不足不再分配给其他软件
  3. 当软件运行完毕后,操作系统将回收该内存空间(注意:操作系统并不清空该内存空间中遗留下来的数据),一遍再次分配给其他软件使用

综上所述:一个软件所分配到的空间中极有可能存在着以前其他软件使用过后的残留数据,这些数据被称之为垃圾数据。所以通常情况下我们为一个变量,为一个数组,分配好存储空间之后都要对该内存初始化!

4. 基本类型指针

#include 
void f(int *p){
//p指向i *p = 100; //*p等价于i}int main(void){
int i = 9; f(&i); //把i的地址发给了p(实参必须是相关变量的地址) printf("%d",i); //i的地址变成了100 return 0;}
f(int * p) 不是定义一个名字叫做*p的形参,而是定义了一个形参名叫做p,类型是int *因为i的变量类型是int,所以p必须是int类型

5. 指针和数组

(1). 指针和下标的关系

int main(void){
int a[5] = {
1,2,3,4,5}; printf("%p\n",a+1); //0012FF70 printf("%p\n",a+2); //0012FF74 printf("%p\n",*a+3); //4 (*a+3 <=> a[0]+3) return 0;}

一维数组名(a) 是一个指针变量,它存放是一个一维数组第一个元素的地址,它的值不能改变,a指向a[0]

下标和指针的关系:a[i] <=> *(a+i)

在这里插入图片描述

(2). 通过指针修改数组的值

#include 
void show_Array(int *p, int len){
p[0]=-1; //p[0] <=> *p int i; for(i=0;i

p[i]就是主函数的a[i],修改p[i]的值等价于修改a[i]的值

*(p+i) == a[i] == p[i]

确定数组需要2个参数(首元素地址 和 数组长度)

(3). 一个指针变量占几个字节

总结:任何类型的指针变量都是占用4个字节。

指针即为地址,指针几个字节跟语言无关,而是跟系统的寻址能力有关,譬如以前是16为地址,指针即为2个字节,现在一般是32位系统,所以是4个字节,以后64位,则就为8个字节。

#include 
int main(void){
int a=1; char b='a'; float c=1.0; void *p; p=&a; printf("a的地址为:0x%x,其字节数为:%d\n",p,sizeof(p)); p=&b; printf("b的地址为:0x%x,其字节数为:%d\n",p,sizeof(p)); p=&c; printf("c的地址为:0x%x,其字节数为:%d\n",p,sizeof(p)); return 0;}

在这里插入图片描述

既然32位,指针变量都占4个字节,那么指针变量前面的类型表示什么含义呢?

  • 虽然所有的指针都只占四个字节,但不同类型的普通变量却占不同的字节数。
  • 一般来说,int占四个字节,char占一个字节.
  • 如果定义指针变量不定义类型,那么它在取*也就是取其中的值的时候,就不知道应该读取几个字节。
  • 而定义了类型之后。如果是int型的就读四个字节,char型的就读一个字节。

(4). 指针和变量的地址关系

指针总是指向变量的第一个字节的地址,即变量的首地址

#include 
int main(void){
double * p; double x=66.6; p = &x; //x占8个字节 double arr[3] = {
1.1, 2.2, 3.3}; double *q; q = &arr[0]; printf("%p\n", q); //0012FF5C q = &arr[1]; printf("%p\n", q); //0012FF64 return 0;}

在这里插入图片描述

6. 指针和函数

#include 
void f(int ** q);int main(void){
int i = 9; int *p = &i; printf("%p\n", p); f(&p); printf("%p\n", p); return 0; } void f(int ** q){
*q = (int *)0xFFFFFFFF; }

通过f函数修改指针变量的值

int ** 类型:表示类型是指针变量的地址

7. 结构体

(1). 为什么会出现结构体

为了表示一些复杂的数据,而普通的基本类型变量无法满足要求

(2). 什么叫结构体

结构体是用户根据实际需要自己定义的复合数据类型。

只有属性,没有方法

定义结构体:

#include 
#include
struct Student{
//struct Student 是一个数据类型名 int sid; //下面是三个成员变量 char name[100]; int age;}; //分号不能省略int main(void){
struct Student st; struct Student st={
1000,"zhangsan",20}; //定义变量的同时赋值 st.sid=99; strcpy(st.name,"lisi"); //C语言必须通过函数给字符数组赋值,不能直接给char类型赋值 st.age=22; struct Student * pst; pst = &st; pst->sid=99; //等价于(*pst).sid 等价于 st.sid}

(3). 使用结构体的两种方式

struct Stduent st = {
1000,"Pudding",20};struct Stduent * pst;pst所指向的结构体变量中的sid这个成员
  • 方式一:st.sid(st是普通变量)
  • 方式二:pst->sid(pst是指针变量)

注意:结构体变量不能加减乘除,但可以相互赋值

(4). 普通结构体变量和结构体指针变量作为函数传参问题

#include 
#include
struct Student{
int sid; char name[100]; int age;};void f(struct Student * pst);void g(struct Student st);void g2(struct Student * pst);int main(void){
struct Student st; f(&st); //输入 g(st) //输出方式一 g2(&st) //输出方式二 return 0;}//这种方式耗内存(至少传递208个字节),耗时间,不推荐void g(struct Student st){
printf("%d %s %d\n",st.sid,st.name,st.age);}void g2(struct Student *pst){
printf("%d %s %d\n",pst->sid,pst->name,pst->age);}void f(struct Student *pst){
(*pst).sid = 99; strcpy(pst->name,"zhangsan"); pst->age = 22;}

8. 动态内存分配和释放

(1). 动态构造一个int类型的一维数组

int *p = (int *)malloc(int len)

  • malloc只有一个int型的形参,表示要求系统分配的字节数

  • malloc函数的功能是请求系统len个字节的内存空间,如果请求分配成功,则返回第一个字节的地址(俗称干地址)转化为一个有实际意义的地址,因此malloc前面必须加(数据类型 *),表示把这个无实际意义的第一个字节的地址转换为相应类型的地址。如:

    int *p = (int *)malloc(50)  表示将系统分配好的50个字节的第一个字节的地址转化为int *型的地址,  更加准确的说是把第一个字节的地址转换为四个字节的地址,  这样p就指向了第一个的四个字节,p+1就指向了第二个的四个字节  p+i就指向了第i+1个的4个字节。p[0]就是第一个元素,p[i]就是第i+1个元素  double *p = (double *)malloc(80)  表示将系统分配好的80个字节的第一个字节的地址转换为double *型的地址,  更加准确的说是把第一个字节的地址转换为八个字节的地址,  这样p就指向了第一个的八个字节,p+1就指向了第二个的八个字节  p+i就指向了第i+1个的8个字节。p[0]就是第一个元素,p[i]就是第i+1个元素
  • free ( p ) 表示:释放p所指向的内存,而不是释放p本身所占用的内存

#include 
#include
int main(void){
int a[5] = {
4,10,2,8,6}; //静态分配内存 int len printf("请输入你需要分配的数组的长度:len = "); scanf("%d",&len); int *pArr = (int *)malloc(sizeof(int) * len); //*pArr = 4; 类似于a[0] = 4; //pArr[1] = 10; 类似于a[1] = 10; //printf("%d %d\n",*pArr,pArr[1]); //我们可以把pArr当作一个普通数组来使用 for(int i=0;i
每个类型的指针变量都存储普通变量第一个字节地址(int *)强制类型转换,告诉编译器第一个字节地址代表了每个单位是一个整型的四个字节静态分配内存:程序从运行之后就一直这么大,在运行过程中不能改变

在这里插入图片描述

(2). 跨函数使用内存

#include 
int main(void){
int * p; fun(&p); return 0;}int fun(int ** q){
*q = (int *)malloc(4);}这样调用fun函数之后指针变量p就指向了一个合法的单元

*p读取指针变量p所指变量的内容

  • java创建对象的底层也是通过动态分配内存
  • A aa = new A();
  • A *pa = (A *)malloc(sizeof(A));

转载地址:http://xhxzi.baihongyu.com/

你可能感兴趣的文章