指针
1.指针用法的初步介绍
指针的简单使用
#include<stdio.h>
int main(void)
{
int* p;//p是变量的名字 int* 表示p变量存放的是int类型变量的地址
int i=3;
p=&i;
/*
1.p保存了i的地址,因此p指向i
2.p不是i,i也不是p,修改p的值不影响i 修改i的值不影响p
*指针变量 就完全等同于 普通变量
例子:
如果p是一个指针变量 并且p存放了普通变量i的地址
则p指向了普通变量i
*p 就完全等同于i
亦或者:
在所有出现*p的地方都可以替换为i
在所有出现i的地方都可以替换为*p
}
p是用来存放要读取数据的地址。*p是让编译器从指定的地址中读取出数据。p输出一个指针的地址,通常是输出一个16进制的数。*p常用在一个和指针类型一致的变量或者常量。
p是一个指针变量的名字,表示此指针变量指向的内存地址 *p表示此指针指向的内存地址中存放的内容
- 指针就是地址,地址就是指针
- 地址是内存单元的编号
- 指针变量是存放地址的变量
- 指针和指针变量是两个不同的概念
指针的重要性
- 表示一复杂的数据结构
- 快速的传递数据
- 使函数返回一个以上的值
- 能直接访问硬件
- 能方便的处理字符串
2.指针的定义
地址
- 内存单元的编号
- 从零开始的非负整数
指针
- 指针的本质就是一个操作受限的非负整数(只能进行相减)
- 指针就是地址,地址就是指针
星号的三种含义
- 乘法
- 定义指针变量
int * p *定义了一个名字叫p的变量,int *表示p只能存放 int 变量的地址
-
指针运算符
改运算符放在已经定义好的变量的前面
如果p是一个已经定义好的指针变量 则
*p表示以p的内容为地址的变量
3.基本类型指针
-
int *p;p是指针变量p=&i;p保存i的地址 所以p指向i -
p指向i 所以*p就是i
-
*p=i是错误写法 要先让p指向 即取p的地址 p=&i -
没有指向的指针变量是垃圾值 如果没有初始化 则没有使用权限
#include<stdio.h>
int main(void)
{
int*q;
int*p;
int i=5;
p=&i;//p取i的地址
q=p;//q取p的地址
printf("%d\n",*q);//输出*q 就是输出 i=5
return 0;
}
经典指针程序 互换两个数字
#include<stdio.h>
void huhuan(int *q,int *p)
{
int t;//如果要互换*q *p的值 那t必须定义成int 不能定义成int *
t=*q;//p是int * *p是int
*q=*p;
*p=t;
}
int main(void)
{
int a=3;
int b=5;
huhuan(&a,&b);
printf("a=%d b=%d\n",a,b);
return 0;
}
huhuan(&a,&b);中不能写成(* a,* b)也不能写成(a,b)
被调函数不能改变主函数的值 如果想改变主函数的值 必须接入主函数的变量地址
p是变量名,&a发送的地址是给p,使得*p为a的值
输入多组数据 使两个数值互换
#include<stdio.h>
void huhuan(int *q,int *p)
{
int t;//如果要互换*q *p的值 那t必须定义成int 不能定义成int *
t=*q;//p是int * *p是int
*q=*p;
*p=t;
}
int main(void)
{
int a,b;
while(~scanf("%d%d",&a,&b))
{
huhuan(&a,&b);
printf("a=%d b=%d\n",a,b);
}
return 0;
}
如何通过被调函数修改主调函数普通变量的值
- 实参(主调函数)必须为该普通变量的地址(&a,&b)
- 形参(被调函数)必须为指针变量 (int * p) p为形参
- 在被调函数中通过
*形参名 =...... 的方式修改主调函数的相关变量的值
4.指针和数组
指针和一维数组
1.一维数组名
一维数组名是个指针常量
它存放的是一维数组的第一个元素的地址
2.下标和指针的关系
如果p是个指针变量 则
p[i]永远等价于*(p+i) p是int * 类型变量
3.一维数组需要两个参数的原因
#include<stdio.h>
void f(int *p,int len)
{
int i;
for(i=0;i<len;++i)
printf("%d ",*(p+i));
printf("\n");
}
int main(void)
{
int a[5]={1,2,3,4,5};
int b[6]={-1,-2,-3,4,5,-6};
int c[100]={1,99,22,33};
f(a,5);
f(b,6);
f(c,100);
return 0;
}
int *p 定义指针变量p,a为数组名 是指针变量。int len 表示数组的长度
*(p+i)等价于p[i]等价于b[i]也等价于*(b+i)
4.指针变量的运算
- 指针变量不能相加 相乘 相除
- 如果两个指针变量指向的是同一块连续空间中的不同存储单元,则这两个指针变量才可以相减
#include<stdio.h>
int main(void)
{
int *p;
int *q;
int a[5];
p=&a[1];
q=&a[4];
printf("p和q所指向的单元相隔%d个单元\n",q-p);
return 0;
}
5.指针变量所占字节
sizeof(数据类型) 功能:返回值为该数据类型所占的字节数
- 假设p指向char类型变量(一个字节)
- 假设q指向int类型变量(四个字节)
- 假设r指向double类型变量(八个字节)
- p q r 本身所占的字节数一样
一个指针变量,无论它指向的变量占几个字节 该指针变量本身只占四个字节
动态内存分配
1.传统数组的缺点
- 数组长度必须实现事先制定,且只能是常整数,不能是变量
- 系统为该数组分配的存储空间会一直存在,直到该函数运行完毕时,数组的空间才会被系统释放
- 数组的长度不能在函数运行的过程中动态的扩充或缩小
- A函数定义的数组,在A函数运行期间可以被其他函数使用,但A函数运行完毕后,A函数中的数组将无法在被其他函数使用
- 传统方式定义的数组不能跨函数使用
2.动态内存分配举例——动态数组的构造,malloc函数的运用
- 要使用malloc函数 必须调价malloc.h文件
- malloc函数只有一个形参 并且形参是整型
- malloc(4) 4 表示请求系统为本程序分配4个字节
- malloc函数只能返回第一个字节的地址
- p本身所占的内存是静态分配的 p所指向的内存是动态分配的
#include<stdio.h>
#include<malloc.h>//使用malloc函数
void f(int *q)
{
*q=200;
}
int main(void)
{
int*p=(int *)malloc(sizeof(int));//sizof(int)返回值是int所占的字节数
*p=10;
printf("%d\n",*p);
f(p);//p是int *类型
printf("%d\n",*p);
return 0;
}
如果void f()函数中加 free (q) 则输出的第二个*p为垃圾值
3.动态一维数组的构造
#include<stdio.h>
#include<malloc.h>//使用malloc函数
int main(void)
{
int a[5];//int 占4个字节 本数组总共包含有20个字节
int len;
int *p;
int i;
//动态的构造一维数组
printf("请输入你要存放的元素的个数:");
scanf("%d",&len);
p=(int*)malloc(4*len);
//对一维数组进行操作
for(i=0;i<len;++i)
scanf("%d",&p[i]);
printf("一维数组的内容是:");
for(i=0;i<len;++i)
printf("%d\n",p[i]);
return 0;
}
p[i]表示的是*(p+i) 理解为地址的值 scanf函数需要取& 取地址符
若printf函数中加&取地址符 则输出结果是该地址 而不是该值
多级指针
-
若p是int *类型 则&p是int ** 类型
#include<stdio.h> int main(void) { int i=10; int *p=&i; int **q=&p; int ***r=&q; printf("%d",***r); return 0; }
( * * r= * q=p=i=10)*
跨函数使用内存
静态变量不能跨函数使用
#include<stdio.h>
void f(int **q)//q是指针变量,无论q是什么类型的指针变量 都占四个字节
{
int i=5;
*q=&i;
}
int main(void)
{
int *p;
f(&p);
printf("%d\n",*p);
return 0;
}
执行完一次后,i被销毁 可p变量依然指向i
动态内存跨函数使用
#include<stdio.h>
#include<malloc.h>
void f(int **q)//q是指针变量,无论q是什么类型的指针变量 都占四个字节
{
*q=(int*)malloc(sizeof(int));
**q=5;//q存放p的地址 *q是p **q是*q
}
int main(void)
{
int *p;
f(&p);
printf("%d\n",*p);
return 0;
}
课后习题
10.12
T1
8 8 4 4 0 0 2 2
T2
ref 有四个元素
T3
ref的地址是指针变量ptr所指的地址
ref+1 表示ref[1]的地址
++ref 无意义 指针变量不能相加
T4
a. * ptr的值是12 ,*(ptr+2)的值是16
b. * ptr的值是12, * (ptr + 2)的值14
T5
a. * ptr的值是12 ,*(ptr+1)的值是16
b. * ptr的值是12, * (ptr + 1)的值14