IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C语言学习笔记(7)之指针(C语言的灵魂) -> 正文阅读

[C++知识库]C语言学习笔记(7)之指针(C语言的灵魂)

1,问题的引入
int a;//定义了一个变量a,类型为int,实质是分配了一个4字节内存单元
a = 100;//把数值100存放到变量a对应的存储单元中去
b = a;//取出变量a的值,然后存放到变量b对应的存储单元中去。
===> 在C语言中,任何一个变量名,都有两层含义:
(1)代表该变量的存储单元 左值(lvalue)
(2)代表该变量的值 右值(rvalue)
而且,我们对变量的访问只有两种情况:
(1)把一个值存到变量的存储空间中去 (write)
(2)从变量的存储空间中取值 (read)
我们知道系统已经把变量名与变量的地址相关联,系统实质上是通过地址来
访问变量的。于是乎,有人提问是不是我们也可以直接通过地址来访问变量呢?
===> 指针

2,指针的概念
地址: 系统把内存以一个字节为单位划分成许多份进行编号,这个编号就是
内存单元中的地址。
在C语言中,指针的概念与地址差不多,你可以认为指针就是有类型的地址。
一个变量的首地址,称为该变量的"指针"。他标志着该变量的内容从哪里开始。

3,指针变量
★指针变量也是一个变量,它是用来保存一个对象的地址的。
指针变量的定义:
类型 指针变量名;
“类型”:指针变量指向的类型
“指向”: 如果我保存了你的地址,那么就说我指向你
eg:
int a;
int p;//定义了一个指针变量p,它的类型是: int
p = &a;//p是一个指针变量名,他指向的类型是int
注意:在32位的处理器里,地址都是32位的,即指针变量分配的空间都是4个字节,
所以把指针变量强制转化为其它类型的指针类型也不会失真。
因此 void
也叫通用指针。

★指针变量的类型决定了该指针变量与整型数据之间的运算,使其实际地址变化之间
的倍率关系。

eg:  int a;
		     char b;
			 int *p1 = &a;
			 char *p2 = &b;
			 printf("%p\n",p1);
			 printf("%p\n",p1+1);
			 printf("%p\n",p2);
			 printf("%p\n",p2+1);

4,如何获取地址
(1)通过取地址符 &
&对象名: 表示取该对象的地址
对象: 变量、数组元素。。。
(2)有些对象的名字本身就表示地址
如: 数组名、函数名。。。
注意: 这两种方式获取到的地址都是有类型的。

5,如何访问指针指向的空间 : *(指向运算符)
(地址) <==> 地址对应的那个变量
(地址)也可作为左值和右值,还可以取地址
*&a <==> a
*& 可直接约掉

注意: 要与乘运算符和定义时的*相区别
	int *p,a=3;
	p = &a;
	printf("%d\n",(*p)*2);

6, 数组与指针
数组元素与普通变量一样,也有自己的地址。
并且数组元素间的地址是连续的,且数组名就是数组的首地址。
eg: int a[10];
int *p;
p = &a[0];
把100赋值为a[0],请问有几种写法
a[0] = 100;
*p = 100;
*a = 100;//数组名就是数组的首地址(首个元素的地址)
那么 *(a+1) ==> a[1]

★ *(p+i) <=> p[i],when i>=0

7, 二维数组与指针
int a[3][4];
二维数组a可以看成元素为int[4]的一维数组,
所以,*(a+i)<=>a[i]指向的是该一维数组的第i个元素,该元素为int[4]类型。
因此,这里需要再指向一次才能指向二维数组的元素:
((a+i)+j) <==> a[i][j],这时元素类型为int型。

表达式(i>=0,j>=0)     		类型/sizeof            		  含义                   值
a+i	              		int[4]*/int[3][4](没有i) 	指向第i行的首地址            &a[i]
*(a+i)+j<=>a[i]+j       int*/ int[4](没有j)      	第i行第j列的元素的地址    	  &a[i][j]
*(*(a+i)+j)<=>a[i][j]       int                  	第i行第j列的元素            a[i][j]
eg:
	 char a[3]={'a','b','c'};
	 char b[2][3]={{'1','2','3'},{'4','5','\0'}};
	 printf("%ld %ld %c\n",sizeof(a),sizeof(a+1),*(a+1));//3 8 b
	 printf("%ld %ld %ld %s\n",sizeof(b),sizeof(b+1),sizeof(*(b+1)),*(b+1));//6 8 3 45

8, 字符串与指针
在C语言中,并没有内置字符串的类型,C语言的字符串是通过char*指针来实现的。

char *str = "ABCDEF";//把保存在rodata段里的字符串的首地址赋值为str
char str1[]="ABCDEF";//定义一个字符数组,并把它的内容初始化为"ABCDEF"

	str: 保存字符串的首地址,即字符'A'的地址。
	str+1: 指向字符'B'的地址。
*(str+1) = '2';//error,因为这里没有定义字符数组,没有分配空间,
               //常量保存在rodata段内,不能被改变
*(str1+1)= '2';//right

"ABCDEF"在C语言中,把该字符串的首地址赋值给了str,由于字符串肯定会有终止符,
系统可以把字符串的内容完整的访问。

9, NULL指针与野指针

(1)NULL也叫空指针,其实是系统定义第一个宏,表示不指向任何空间。
		#define  NULL ((void*)0)
		所以NULL在逻辑运算中表示假
		NULL不能被访问,否则就会报段错误。
(2)野指针
	野指针不是NULL指针,而是指向非法分配空间的指针
		野指针的成因有两种
		1)指针变量未初始化
		2)指针变量被free或delete后没有置为NULL,让人误以为p还是个合法的指针
eg:
	(1) void swap(int *a,int *b)//error
		{
			int *p;//p是一个野指针
			*p = *a;
			*a = *b;
			*b = *p;
		}
	(2)
		char *p = (char*)malloc(100);//在动态内存区域分配100个字节的空间
		strcpy(p,"hello");
		free(p);//已经把分配的空间释放掉了
		....
		....
		if( p!= NULL)
		{
			strcpy(p,"word");
		}

11, 数组指针与指针数组
int a[10];//定义了一个有10个元素的数组a,每个元素都是int型
如果我们要定义一个指针p,来保存a的地址。
该如何定义?

typeof(a)  *p;
==> int[10] *p;
==> int (*p)[10];
	p就是一个指针,指向一个数组(int[10]),那么我们把p叫做数组指针
因为'*'的结合性较低,所以这里要把(*p),表示定义的是指针。
★二维数组名就是一个数组指针,所以数组指针的用法就是二维数组名的用法。

int *p[10];
这里的p是一个数组,里面有10个元素,每个元素都是int *类型,
那么我们把p叫做指针数组。

eg:  int (*p1)[10];//定义了一个数组指针变量
     int *p2[10];//定义了一个指针数组
	 printf("%d %d\n",sizeof(p1),sizeof(p2));//8  80

12, main的参数
在unix/linux下面,main函数的原型,应该是如下的:
int main(int argc, char *argv[])
{
}
在操作系统调用你的可执行程序时(调用你的main函数),允许带参数,
只不过这些参数都是字符串类型的(char *)
argc: argument count表示运行你的程序时,参数的个数(程序名,也是一个参数)
argv: argument vector 参数字符串指针的数组
eg: ./a.out 1 2

13, 二级指针与多级指针
其实main函数原型也可写成如下模式
int main(int argc, char **argv)
{}

可见指针数组就是个二级指针
二级指针就是能指向两次的指针,一般有以下两种理解方式
(1) 指针变量的地址
	eg:  int a=100;
	     int *p = &a;
		 int **p2 = &p;//p2就是一个二级指针变量,它的类型是int **
		 printf("%d %d %d\n",a,*p,**p2);
		 
(2)指针数组
	如果一个数组的元素是指针,则该数组名就是二级指针。
	同理,如果一个数组的元素是二级指针,则该数组名就是三级指针。
	....

	在C语言中,char *可以表示字符串。其实指针也可以表示一个已定义了的数组。
	它们的区别是字符串有终止符'\0'来确定长度,而数组必须要我们自己给定长度。

14, 函数指针
函数指针变量就是用来保存函数地址的变量。
函数指针变量的定义:
指向的函数返回值类型 (*函数指针变量名)(指向的函数形参列表);

通过函数指针调用指向的函数:
	(*函数指针)(实参列表)
	或
	(函数指针)(实参列表)
	
函数指针的用法:
	1)线程池
	2)回调函数

回调函数就是一个被作为参数传递的函数。
用户把需要调用的函数的指针作为参数传递给一个函数,以便该函数在处理相应事件的时候可以灵活的使用不同
的方法。
应用示例:一般操作系统都实现了中断机制,但用户不能直接定义中断处理函数,只能在中断处理函数中再调用
用户自定义的回调函数。
	
☆函数指针数组
	void (*a[3])(int,int);//定义了一个函数指针数组a,他有三个元素,每个元素都是函数指针
	                      //返回值为void,参数类型为(int,int)的函数指针。

15, 指针作为函数参数
由于形参不能改变实参的值,被调函数想传递数据给主调函数一般用return返回。
除此之外还有两种方式:
(1)访问全局变量
(2)带指针作为函数参数

16, 动态内存分配
malloc free realloc calloc

NAME
malloc, free, calloc, realloc - allocate and free dynamic memory

SYNOPSIS
#include <stdlib.h>

malloc: memory allocate,用来在进程的动态内存区域(堆)分配一块内存,
		并且把该分配的内存的首地址作为函数的返回值返回。
		"进程的动态内存区域":也是一个内存区域,只不过该区域的内存的生存期
		是随进程持续性。一旦分配,如果不手动释放(free),那么就一直存在,直到进程退出。
   void *malloc(size_t size);
		@size: 你要分配的动态内存的大小,单位为字节
		返回值:
			如果成功,将返回分配空间的首地址
			如果失败,返回NULL
			
free: 用来释放malloc/calloc申请的动态内存区域
   void free(void *ptr);
		@ptr: 你要释放那段内存的首地址(malloc/calloc的返回值)
   
calloc用来分配一段内存空间用来存放数组 
   calloc(n,size) <==>  malloc(n*size);
   void *calloc(size_t nmemb, size_t size);
		@nmemb : 数组元素的个数
		@size : 每个元素占多少个字节
		返回值:
			如果成功,将返回分配空间的首地址
			如果失败,返回NULL
			
realloc: repeat allocate
	1) 改变ptr指向的那段动态内存的大小
		ptr指向的原来那段内存空间的内容不变,增加和减少的内存都不会初始化。
	2) 如果ptr == NULL
		那么realloc(NULL,size) <==> malloc(size)
	3) 如果ptr!=NULL,且size==0
	    那么realloc(ptr,0) <==>  free(ptr)
   void *realloc(void *ptr, size_t size);

进程内存空间布局
进程内存空间布局

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-23 11:16:20  更:2021-09-23 11:17:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 22:41:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码