指针就是内存地址,使用指针访问变量,就是直接对内存中的数据进行操作。
C语言灵魂——指针
1.指针的简单用法
- 初识指针
/*
2021年1月24日13:14:41
初识指针
*/
# 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 的值互不影响
if (* p == i)
{
printf("*p 和 i 的值相等:");
printf("i = %d\n", * p); // 3.如果一个指针变量指向了某个普通变量则 *指针变量 就等同于普通变量 * p == i
}
else
printf("* p != i\n");
return 0;
}
/*
----------------------------------------------
在VC++6.0中运行的结果为:
*p 和 i 的值相等:i = 3
思考: p = &i; *p = i;
* & 相当于逆运算
*p 是以p的内容为地址的变量
----------------------------------------------
*/
/*
2021年1月26日10:51:13
初识指针
《C语言从入门到精通》
*/
# include <stdio.h>
int main(void)
{
int i, * p;
char m, * q;
i = 6;
m = 'A';
p = &i;
q = &m;
printf("i = %d, i的地址为:%d\n", i, &i);
printf("p = %d, *p = %d, p的地址为:%d\n", p, *p, &p);
printf("m = %c, m的地址为:%d\n", m, &m);
printf("q = %d, *q = %d, q的地址为:%d\n", q, *q, &q);
return 0;
}
/*
-------------------------------------------------------------
在VC++6.0中运行结果为:
i = 6, i的地址为:1703724
p = 1703724, *p = 6, p的地址为:1703720
m = A, m的地址为:1703716
q = 1703716, *q = 65, q的地址为:1703712
结论:1.每个变量都有不同的地址
2.p表示i的地址 p = &i;
3.p指向i
4.*p访问变量i的值 *p = i;
-------------------------------------------------------------
*/
2.指针的重要性
- 1.表示复杂的数据结构
- 2.快速传递数据
- 3.使函数返回多个值
- 4.直接访问硬件
- 5.处理字符串
- 6.理解面向对象的基础
3.指针的定义
1.地址
- 内存的单元编号
- 从零开始的非负整数
2.指针
- 指针就是地址
- 指针变量就是存放内存单元编号的变量
4.指针的分类
1.基本类型指针
- 程序一:交换两个数的值
/*
2021年1月26日11:35:37
交换两个数的值
*/
# include <stdio.h>
int main(void)
{
int i, j;
int * p, * q, * m;
p = &i;
q = &j;
printf("请输入变量i 和 变量j: \n");
scanf("%d %d", &i, &j);
if (*p < *q)
{
m = p; // 源代码必须写为:m = p; 目的是:交换p q存储单元的值
p = q;
q = m; /* 不能写为 * m = * p; 原因是:* m 仅仅声明了
但没有初始化 没有明确的指向 他可能指向一个不存在的存储区域
变量 i 存储在一个不存在的区域内 当然会报错 */
}
printf("i的值为%d i的地址值为:%d *p = %d\n", i, &i, *p);
printf("j的值为%d j的地址值为:%d *q = %d\n", j, &j, *q);
return 0;
}
/*
-----------------------------------------------------------
在VC++6.0中运行的结果为:
请输入变量i 和 变量j:
2 3
i的值为2 p的值为:1703724 *p = 3
j的值为3 q的值为:1703720 *q = 2
-----------------------------------------------------------
*/
- 常见错误1
指针需要初始化 否则指针默认空指针 没有p = &i; p无法指向i
# include <stdio.h>
int main(void)
{
int i = 8;
int * p;
* p = i; // *p 与 i 的地址不同, *p 仅与 i 在数值上相同,需要初始化
printf("%d\n", * p);
return 0;
}
- 常见错误2
# include <stdio.h>
int main(void)
{
int i = 8;
int * p;
int * q;
p = &i;
// *q = p; error 类型不同
// *q = *p; error q没有分配地址空间
// p = q; error q 是未知变量 赋值给 p p 也将变为垃圾值 *q 当然也无法输出(内存空间未分配)
q = p; // 正确 p 是 i 的地址 q 是地址变量 即 q 也为 i 的地址(q---> i) 所以 *q 为 i
printf("%d\n", *q);
q = &(*p); // 正确 q---> i
printf("i = %d\n", *q);
return 0;
}
/*
-------------------------------------------
在VC++6.0中运行结果为:
8
i = 8
-------------------------------------------
*/
- 指针交换两个数的值
/*
2021年1月24日18:15:36
指针交换两个数的值
目的:1.自定义函数与主函数通过指针联系起来。
2.主函数的实参只能单向调用自定义函数的形参。
3.指针可以使主调函数返回多个值 不用指针两个数不能交换,
函数调用结束后实参的值任然不变。
*/
# include <stdio.h>
void swap(int * p, int * q)
{
int t;
t = * p; // *p *q 为值
* p = * q;
* q = t;
}
int main(void)
{
int a = 5;
int b = 2;
swap(&a, &b); // p = &a
printf("a = %d b = %d\n", a, b);
return 0;
}
/*
----------------------------------------
在VC++6.0中运行结果为:
a = 2 b = 5
----------------------------------------
*/
※ *的含义:
1.乘法
2.定义指针变量 int * p;
3.指针运算符 * p = i;
2.指针和数组
1.指针和一维数组
- 数组名
- 一维数组名是个指针常量 例:a = &a[0] (×) a是一个常量
- 他存放的是一维数组第一个元素的地址 例:a == &a[0] (√)
- 下标和指针的关系
- 如果p是个指针变量,则 p[i] == *(p+i)
- 指针变量的运算(地址的运算)
- 移动指针:通过加减一个整数,实现对指针位置的移动
- 假如数据类型为整型:4字节
/*
2021年1月26日16:06:37
指针的运算①
*/
# include <stdio.h>
int main(void)
{
int a = 2;
int b = 5;
int * p, * q;
p = &a;
q = &b;
printf("p的值为:%d p的地址为:%d\n", *p, p);
printf("q的值为:%d q的地址为:%d\n", *q, q);
printf("p-1的地址为:%d\n", *(p-1)); // *(p-1) p指向的地址减一个存储单元即后移4字节的地址存储的数据
printf("p的地址-1后的值为:%d\n", *p-1); // *p-1 p指向的存储单元的值减一
return 0;
}
/*
---------------------------------------------------------------------------------------------------------------
在VC++6.0中运行结果为:
p的值为:2 p的地址为:1703724
q的值为:5 q的地址为:1703720
p-1的地址为:5
p的地址-1后的值为:1
结论:*(p-1) 和 b 的值相同
原因:a、b占用连续的存储单元 *(p-1)就相当于p的地址后移4字节的地址存储的数据即为b的值 所以*(p-1) == b。
---------------------------------------------------------------------------------------------------------------
*/
- 两指针相减
- 两指针比较
- sizerof(数据类型or 变量名) 功能:返回该数据所占的字节数
- 一个指针变量 无论指向什么数据类型 都占用四字节 因为输出占用32根线 每一根线表示一位 有0 1 两种状态 一字节又是八位 所以占用四字节。
2.指针和二维数组
一、动态内存分配
- 1.数组长度必须事先制定,且只能是整数,不能是变量
- 2.传统的数组 分配的内存空间程序员不能手动释放,数组一旦定义,存储空间就被分配了,直到函数运行结束,空间被释放。
- 3.数组的长度不能在函数运行过程中扩缩。
- 4.函数内部的传统数组相当于局部变量 使用完后空间被自动释放,不能供其他函数使用
二、动态存储的意义
- 1.静态数组有很多缺陷,动态数组完美解决。
三、动态内存分配实例
- 程序一:malloc 函数的简单介绍
/*
2021年1月24日19:27:28
malloc 函数的简单介绍
*/
# include <stdio.h>
# include <malloc.h> // 头文件必须存在
int main(void)
{
int i= 5; // 静态分配4字节
int * p = (int *)malloc(4); /* 1.包含头文件
2.malloc只有一个形参 且必须为整型
3.malloc(4) 请求系统分配4字节
4.只能返回第一个字节的地址
5.强制类型转换目的是为了说明数据类型
6.malloc函数都为动态存储
7.p本身所占的内存是静态分配的 p指向的是动态存储
8.int * p = (int *)malloc(4); 分配了八字节 变量占4字节 p指向的地址占4字节
*/
*p = 5; // 数据相同 但动态分配
printf("HH\n");
printf("i = %d *p = %d\n", i, *p);
free(p); // free(p)表示把p所指向的内存给释放掉
printf("i = %d *p = %d\n", i, *p); // *p 错误:空间已经被释放 *p 无法指向任何数据 在其他编译器中会报错
return 0;
}
/*
--------------------------------------------
在VC++6.0中运行的结果为:
HH
i = 5 *p = 5
i = 5 *p = -572662307
结论:*p = -572662307 垃圾值 因为空间被释放
--------------------------------------------
*/
- 程序二:malloc 的函数用法
/*
2021年1月27日14:06:25
malloc 的函数用法
*/
# include <stdio.h>
# include <malloc.h>
void f(int * p)
{
*p = 2;
}
int main(void)
{
int * p = (int *) malloc(sizeof(int));
*p = 10;
printf("%d\n", *p);
f(p);
printf("%d\n", *p);
return 0;
}
/*
------------------------------------------
在VC++6.0中运行的结果为:
10
2
------------------------------------------
*/
程序三、动态一维数组实例
/*
2021年1月27日15:12:53
动态一维数组实例
*/
# 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); // 动态构造了一个数组 类似 int pArr[len];
// 对一维数组进行赋值
printf("对数组进行赋值:");
for (i=0; i<len; i++)
scanf("%d", &pArr[i]);
// 对一维数组进行输出
printf("一维数组的内容是:\n");
for (i=0; i<len; i++)
printf("pArr[%d] = %d\n", i, pArr[i]);
return 0;
}
/*
----------------------------------------------------------
在VC++6.0中运行结果为:
请输入要存放的元素的个数:5
对数组进行赋值:88 55 66 99 44
一维数组的内容是:
pArr[0] = 88
pArr[1] = 55
pArr[2] = 66
pArr[3] = 99
pArr[4] = 44
----------------------------------------------------------
*/
3.指针和函数
4.指针和结构体
5.多级指针
多级指针目的是为了跨函数使用
/*
2021/1/30-21点25分
初识多级指针
*/
# include <stdio.h>
int main(void)
{
int i = 10;
int * p = &i;
int ** q = &p;
int *** m = &q; // m = &q; m 为 int *** 类型 只能存放 int ** 类型变量的地址
printf("i = %d\n", *** m); // VC6.0中运行结果为:i = 10
return 0;
}