C语言——指针
1、相关概念:
- 指针就是地址,地址就是指针
- 指针就是内存单元的编号
- 指针变量是存放地址(指针)的变量
- 指针和指针变量是两个不同的概念
- 但是要注意,通常叙述时会把指针变量简称为指针,实际他们的含义不同。
#include <stdio.h>
int main(void)
{
int * p;//int * p不表示定义了一个名字叫做*p的变量
//int * p应该理解为:定义了一个只能指向(存放)int类型的地址的指针变量p。
int i = 3;
int j;
p = &i;//将 i 的地址存放 在指针变量p内 ,作用是 p 指向 i
/*
1、p保存了 i 的地址,因此p指向 i
2、p不是i,i 也不是 p,更准确的说,修改 p 的值不影响i,
3、如果一个指针变量指向某个普通变量,则*指针变量就 完全等价于 普通变量
例子:
如果p是个指针变量,并且p存放了普通变量i的地址,
则p指向了普通变量 i;
*p完全等同于 i ;
或者说:在所有出现*p的地方都可以写为 i ;
在所有出现 i 的地方都可以写为 *p ;
4、*p 表示以p的内容为地址的变量,
*/
j = *p; //等价于 j = i;
printf("i = %d, j = %d, *p =%d ", i, j, *p);
return 0;
}
2、指针经典程序:
#include <stdio.h>
/*
*编写函数能够互换a , b的值
*/
//不能完成互换功能
void HuHuan1(int a, int b)
{
int t;
a = t;
a = b;
b = t;
}
//不能完成互换
void HuHuan2(int *p, int *q )
{
int *t;//互换p和q的值,则t的类型应该和pq相同
t = q;//仅仅交换了地址,而a,b本身的值未改变
q = p;
p = t;
}
//可以完成互换
void HuHuan3(int *p, int *q )
{ //接收a,b的是q,p而不是*q,*p。
int t;
t = *q; //p是int *, *p是int
*q = *p;
*p = t;
}
int main(void)
{
int a = 3;
int b = 5;
//HuHuan1(a, b); //执行完以后就释放了,所以互换不成功
//HuHuan2(&a, &b);//不能完成互换,因为该函数只是互换了qp的地址
//HuHuan(*a, *b);是错误写法
HuHuan3(&a, &b);
printf("a = %d, b = %d\n", a, b);
//总结: p是a的地址,*p=a;q是b的地址,*q=b,要交换的不是地址,而是地址和值!!
return 0;
}
3、数组与指针的关系
- 指针和一维数组:
一维数组名是个指针常量,它存放的是一维数组第一个元素的地址,即:a == &a[0]
#include <stdio.h>
int main(void)
{
int a[5];
printf("%#X\n", &a[0]);//用16进制输出a[0]的地址:0X62FE00
printf("%#X", a); //将一维数组名输出,输出:0X62FE00
//总结:说明上面:“一维数组名”是个指针常量,它存放的是一维数组第一个元素的地址 即:a == &a[0]
return 0;
}
- 程序二:
/*
用函数输出任何数组的内容 ,需要两个参数 :数组名(首地址)和长度
*/
#include <stdio.h>
//函数f输出任何数组的内容
void f(int * pArr ,int len)
{
int i;
for(i=0; i<len; i++)
printf("%d ", *(pArr+i));
printf("\n");
}
int main(void)
{
int a[5] = {1,3,4,2,9};
int b[6] = {2,5,6,3,1,9};
int c[100] = {99,1,33};
f(a,5); //a是int *
f(b,6);
f(c,100);
return 0;
}
4、指针的运算
- 指针不能+,*,/
- 如果指针变量指向的是同一块连续空间中的不同单元,则可以相减。
#include <stdio.h>
int main(void)
{
int *p;
int *q;
int a[5];
p = &a[2];
q = &a[4];
printf("%d", q-p);
}
- 一个指针变量,无论它指向的变量占几个字节,该指针变量本身只占四个字节。
5、动态内存分配–malloc函数的使用
- sizeof的使用:
#include <stdio.h>
#include <malloc.h>
int main(void)
{
int * p = (int *)malloc(sizeof(int));//sizeof(int)返回值是int所占的字节数
}
- malloc函数的使用
#include <stdio.h>
#include <malloc.h>
int main(void)
{
int i = 5;//静态分配
int * p = (int *)malloc(4);
/*
1.要使用malloc函数,必须添加<malloc.h>头文件
2. mallco函数只有一个形参,并且形参都是整形;
3.(4)表示请求系统为本程序分配4个字节;
4.malloc函数只能返回第一个字节的地址;
5.上面的代码(第6行) 分配了8个字节,p变量占4个字节,p所指向的内存也占4个字节
6. p本身所占的内存是静态分配的,p所指向的内存是动态分配的
*/
* p = 5;//*p表示一个int变量,只是他的内存分配方式和第六行的分配方式不一样
free(p); //表示把p所指向的内存释放掉, p本身的内存是静态的, 不能手动释放,只能在 所在函数终止时系统释放,
return 0;
}
6、动态数组构造
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CyarJeCE-1598249039288)(D:\C语言\WorkPlace\基础知识\指针\Snipaste_2020-08-17_17-29-57.jpg)]
# include <stdio.h>
# include <malloc.h>
int main(void)
{
int a[5];
int len;
int *pArr;//存放前四个字节
int i;
//动态构造一维数组
printf("请输入你要存放的元素个数:");
scanf("%d" ,&len);
pArr = (int *)malloc(4 * len);//本行动态构造了一个一维数组,数组名是pArr,类型是int型,其功能类似于 int pArr[len];
//对一维数组进行操作:对动态一维数组进行赋值
for(i=0; i<len; i++)
scanf("%d", &pArr[i]);
//对一维数组进行输出
for(i=0; i<len; i++)
printf("%d\n", pArr[i]);
free(pArr);//释放掉动态分配的数组
return 0;
}
7、多级指针
# include <stdio.h>
int main(void)
{
int i = 10;
int *p = &i;
int **q = &p;
int ***r = &q;
//r = &p; //error 因为r存放的是int***类型,r只能存放 int**类型的地址
printf("i = %d", ***r); //输出i=10;
return 0;
}
- 理解以下代码
#include <stdio.h>
void f(int ** q)
{
//*q就是p
}
void g()
{
int i = 10;
int *p = &i; //p是int*类型,则 &p 是int**类型
f(&p);
}
int main(void)
{
g();
return 0;
}
8、跨函数使用内存(重点)
- 静态内存不能跨函数使用
#include <stdio.h>
void f(int ** q)//q是个指针变量,占4个字节 ,用来指向p的地址
{
int i = 5;
//*q等价于p,
//*p = i;erro 因为*q=i;等价于p = i;p 是一个指针变量,这样写是错的
*q = &i; //
}
int main(void)
{
int *p ;
f(&p);//p是int*类型,则 &p 是int**类型
printf("%d\n", *p);//输出:5;本句语法没有问题,但是逻辑上有问题
//因为函数f()中的 i 是静态变量,f()执行完之后就已经释放
//指针是可以一直保存 i 的地址没错,但是不应该读出i的值(i=5)但是被指针读出来了。所以这个程序是有问题的
return 0;
}
- 动态内存可以跨函数使用
#include <stdio.h>
#include <malloc.h>
void f(int **q)
{
*q = (int *)malloc(sizeof(int));//sizeof(数据类型) 返回该数据类型所占的字节数
//上面的代码等价于:p = (int *)malloc(sizeof(int));
//q = 5; //error
//*q = 5;//p = 5; p是指针变量,只能存放地址
**q = 5;//*p = 5;
}
int main(void)
{
int *p;
f(&p);
printf("%d\n", *p); //此时这个程序在逻辑和语法上都没错
return 0;
}