首页 > 其他分享 >指针

指针

时间:2023-01-12 18:24:27浏览次数:33  
标签:arr int 地址 pa printf 指针

1. 内存

 

1.1 什么是内存

 

内存是一种存储器,用来存放数据, 程序,所有的程序都是加载到内存中运行的

 

1.2 内存结构

 

内存由两部分组成,存储单元地址,和存储空间组成

每一个存储单元地址,存放1个字节,8个比特位

 

 

1.3 内存的大小

 

有多少个存储单元地址?

地址的个数由机器地址线决定,在32位的机器上,地址为32,地址的个数为 232 = 4,294,967,296

4,294,967,296 个 字节   ----->   4GB

 

1.4 如何理解内存

 

内存可以理解为一个房子,通过访问门牌号码,就可以找到相对应的房间

通过访问内存地址单元,就可以取出存储空间中的数据

 

 

2. 指针

 

2.1 什么是指针,指针变量

 

指针是存储单元地址,也就是地址

指针变量是存放地址的变量

 

例子:

#include <stdio.h>
int main()
{
    int a = 1;
    int* pa = &a;
    printf("0x%p", pa);
    return 0;
}

 

 

解析:

 

#include <stdio.h>
int main()
{
    int a = 1;
    int* pa = &a;
    printf("0x%p", pa);
    return 0;
}

int a = 1;   在内存中开辟4个字节,存入1

int* pa = &a;   &a取出变量a的地址,存入指针变量pa中

printf("0x%p", pa);  最后,以地址的形式打印指针变量pa的值,也就是变量a的地址

 

pa在这个例子中就是一个指针变量,pa存储变量a的地址

 

 

2.2 如何理解指针和指针变量

 

指针是地址, 指针变量是存储地址的变量

#include <stdio.h>
int main()
{
    int a = 1;
    int* pa = &a;
    printf("0x%p", pa);
    return 0;
}

int *pa = &a;

* 表示pa,  是一个指针变量,存储地址

int 表示, pa 存储的变量a的类型是 int

 

2.3 &取地址,*间接寻址操作符

 

&, 表示取出一个变量的起始地址

*, 表示访问内存单元地址

#include <stdio.h>
int main()
{
    int a = 10;
    int* pa = &a;
    *pa = 20;
    prinf("%d\n",*pa);
}

 

 

&a, 取出变量a的起始地址,存入指针变量pa中

*pa = 20, 此时,pa存储的是变量a的地址, *pa = 20,表示访问a的地址,将存储空间中的值改为20

 

2.4 指针变量的大小

 

指针变量存储一个变量的地址,存储地址

在32位地址线机器上,地址为32位,指针变量大小为4个字节

#include <stdio.h>
int main()
{
	int a = 0;
	int* pa = &a;
	printf("%d\n", sizeof(pa));
	return 0;
}

 

3. 指针类型

口语中的指针就是指针变量

 

3.1 指针类型

char  *pc = NULL;
int   *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL;

指针类型,根据存储变量的类型决定, 强制类型转换除外

 

3.2 指针类型的意义

 

指针变量的大小根据机器地址线决定,32位为4个字节, 64位为8个字节

既然指针变量的大小都是固定的,指针类型有什么意义?

 

1. 指针类型决定 *间接寻址 访问几个字节

 

#include <stdio.h>
int main()
{
	int a = 0x11223344;
	int* pa = &a;
	*pa = 0;
	printf("%d\n", a);
  
}

 

#include <stdio.h>
int main()
{
	int a = 0x11223344;
	char* pa = (char*)&a;
	*pa = 0;
	printf("%d\n", a);
  
}

 

 

当 pa 为整型指针时,*访问4个字节,*pa = 0, 同时访问4个内存单元地址中的内存空间,然后赋值为0

当 pa 为字符指针时, * 只能访问1个字节, *pa = 0, 只能访问1个地址中的内存空间,所以只能将一个地址赋值为0

 

2. 指针类型决定 指针的步长

 

类型决定,指针+1跳过几个字节

整型指针 + 1, 跳过4个字节

字符指针 + 1, 跳过1个字节

 

#include <stdio.h>
int main()
{
	int a = 0;
	int* pa = &a;
	printf("%p\n", pa);
	printf("%p\n", pa + 1);
	return 0;
}

 

 

 

#include <stdio.h>
int main()
{
	char a = 0;
	char* pa = &a;
	printf("%p\n", pa);
	printf("%p\n", pa + 1);
	return 0;
}

 

 

4. 指针运算

 

4.1 指针 +- 整数

#include <stdio.h>
int main()
{
	int a = 1;
	int* pa = &a;
	printf("%p\n", pa);
	printf("%p\n", pa + 1);
	printf("%p\n", pa - 1);
	return 0;
}

 

 

整型指针 + 1, 向地址高位移动4个字节

整型指针 - 1, 向地址低位移动4个字节

 

4.2 指针 - 指针

#include <stdio.h>
int main()
{
    int arr[10] = { 0 };
    printf("%d\n", &arr[9] - &arr[0]);
    return 0;
}

 

 

指针 - 指针的值是两个指针之间的元素个数

 

 

// 求字符串长度
#include <stdio.h>

int len1(char* str)
{
	int count = 0;
	char* ps = str;
	while (*str != '\0')
	{
		str++;
	}
	return str - ps; // 指针 - 指针
}
int main()
{
	char arr[] = "abcdef";
	int res = len1(arr);
	printf("%d\n", res);
	return 0;
}

 

 

4.3 指针关系运算

 

#include <stdio.h>
int main()
{
	int arr[5] = { 0 };
	int count = 1;
	for (int* pa = &arr[0]; pa < &arr[5]; pa++)
	{
		*pa = count;
		printf("%d ", *pa);
		count++;
	}
	printf("\n");
}

 

 

pa < &arr[5],比较的是地址的高低位

 

 

 

5. 二级指针

 

5.1 什么是二级指针

#include <stdio.h>
int main()
{
	int a = 1;
	int* pa = &a;	    // 一级指针 pa
	int** ppa = &pa;	// 二级指针 ppa
	return 0;
}

 

二级指针是一个指针变量,存储一级指针变量的地址 

 

5.2 如何理解二级指针

 

#include <stdio.h>
int main()
{
	int a = 1;
	int* pa = &a;	    // 一级指针 pa
	int** ppa = &pa;	// 二级指针 ppa
	return 0;
}

只要是一个变量,都会在内存中开辟一块存储空间

指针也是一个变量,在内存中也会有地址

&pa, 取出一级指针变量pa的地址存储入ppa中

ppa二级指针,存储一级指针pa的地址

 

int * pa = &a, * 表示pa是一个指针变量, int 表示pa存储a的类型为 int

int * *ppa = &pa,  *ppa 表示ppa是个指针变量, int*表示ppa存储的pa的类型是一个一级整型指针int* 

 

5.3 二级指针的使用

#include <stdio.h>
int main()
{
	int a = 1;
	int* pa = &a;	    // 一级指针 pa
	int** ppa = &pa;	// 二级指针 ppa
	printf("%d\n", a);
    
	*(*ppa) = 2;
	printf("%d\n", a);
	return 0;
}

 

(*ppa), 表示访问ppa的存储空间, 空间内存放的是一级指针pa的地址

*(*ppa) --> 通过pa的地址,访问pa的存储空间, 变量a的地址

(*ppa) = (pa) ----> *(*ppa) = *(pa)

所以,实际上访问的是a的存储空间

*(*ppa) = 2 , 将空间的值改为2

 

5.4 三级指针

 

三级指针就是存储二级指针的地址

#include <stdio.h>
int main()
{
	int a = 1;
	int* pa = &a;	    // 一级指针 pa
	int* *ppa = &pa;	// 二级指针 ppa
	int** *pppa = &ppa; // 三级指针 pppa
	return 0;
}

*pppa,表示pppa是一个指针, int** 表示pppa存储的ppa的类型是二级整型指针  

 

6. 字符指针

 

6.1 常量字符串的值是什么

#include <stdio.h>
int main()
{
	char* str = "abcdef";
	printf("%s\n", str);
	return 0;

}

 

常量字符串的值等于首字符的地址,指针变量str, 存储的是字符a的地址

%s, 表示打印\0之前所有的字符

 

6.2 C/C++ 存储常量字符串的规则

#include <stdio.h>
int main()
{
    char str1[] = "hello bit.";
    char str2[] = "hello bit.";
    const char* str3 = "hello bit.";
    const char* str4 = "hello bit.";
    if (str1 == str2)
        printf("str1 and str2 are same\n");
    else
        printf("str1 and str2 are not same\n");

    if (str3 == str4)
        printf("str3 and str4 are same\n");
    else
        printf("str3 and str4 are not same\n");

    return 0;
}

C/C++ 会把常量字符串存储到一个单独的存储区中 

当多个指针同时存储相同的常量字符串时,指针存储相同的首字符地址

 

7. 指针和数组

 

7.1 区分指针和数组

 

指针和数组是两个不同的对象

指针是存储地址的变量,数组是一组相同类型元素的集合

#include <stdio.h>
int main()
{
    int arr[5] = {0}; // 数组arr
    int* pa = arr;    // 指针pa
    return 0;
}

 

7.2 数组名 = 数据首元素地址

 

#include <stdio.h>
int main()
{
	int arr[5] = { 0 };
	printf("0x%p\n", arr);
	printf("0x%p\n", &arr[0]);
	return 0;
}

 

 

7.3 通过指针访问数组

 

#include <stdio.h>
int main()
{
	int arr[5] = { 1,2,3,4,5 };
	int* pa = arr;
	for (int i = 0; i < 5; i++)
	{
		printf("%d ", *(pa + i));
	}
	printf("\n");
	return 0;
}

 

 

8. 指针数组

 

8.1 什么是指针数组


#include <stdio.h>
int main()
{
	char* arr[3] = { "aaa","bbb","ccc" }; //字符指针数组
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		printf("%s\n", *(arr + i));
	}
	return 0;
}

 

#include <stdio.h>
int main()
{
	int arr1[5] = { 1,2,3,4,5 };
	int arr2[5] = { 2,3,4,5,6 };
	int arr3[5] = { 3,4,5,6,7};

	int* arr[3] = { arr1, arr2, arr3 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			printf("%d ", *(arr[i] + j));
		}
		printf("\n");
	}
}

指针数组是存储地址的数组

 

9. 数组指针

 

9.1 &数组名,数组名的区别

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	// arr
	printf("%p\n", arr);
	printf("%p\n\n", arr + 1);

	// &arr
	printf("%p\n", &arr);
	printf("%p\n", &arr + 1);
}

arr, 是数组首元素的地址

&arr, 是数组的地址

 

9.2 什么是数组指针

#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int (*pa)[10] = &arr; //数组指针 

}

数组指针是存储数组地址的指针

 

9.3 如何理解数组指针

#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int (*pa)[10] = &arr; //数组指针 

}

(*pa),表示pa是一个指针,

[10], 表示pa存储的数组有10个元素

(*pa)前面的int,表示每一个元素的类型是int

 

9.4 数组指针的使用

#include <stdio.h>

void print(int (*pa)[5], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{

		int j = 0;
		for (j = 0; j < col; j++)
		{
			printf("%d ", (*(pa + i))[j]);
		}
		printf("\n");
	}
}

int main()
{
	int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6}, {3,4,5,6,7} };
	print(arr, 3, 5);
	return 0;
}

 

 

解析:

二维数组的数组名 = 二维数组第一行的地址

 int (*pa)[5],接收第一行地址, 第一行有5个元素,类型是int

( *(pa + i) ) [j] 

(pa + i),pa+0,就是第一行的地址,以此类推

( *(pa + i) )[j], 访问第几行的地址,拿到数组元素, 然后用下标j,锁定元素

 

 

10. 函数指针

 

10.1 什么是函数指针

#include <stdio.h>

int sum(int x, int y)
{
	return x + y;
}

int main()
{
	int (*pf)(int, int) = &sum; // 函数指针
	int res = (*pf)(1, 2);
	printf("%d\n", res);
	return 0;
}

函数指针,存储函数地址的指针

 

10.2 如何理解函数指针

#include <stdio.h>

int sum(int x, int y)
{
	return x + y;
}

int main()
{
	int (*pf)(int, int) = &sum;
	int res = (*pf)(1, 2);
	printf("%d\n", res);
	return 0;
}

 int (*pf) (int, int)

(*pf), * 表示pf是一个指针

(int, int), 表示pf存储的是函数地址,函数有两个参数

int,表示函数的返回类型是int

 

11. 函数指针数组

 

11.1 函数指针数组

#include <stdio.h>

int main()
{
	int (*pf[3])(int, int);	//函数指针数组
	return 0;
}

函数指针数组,是存储函数地址的数组

 

11.2 如何理解函数指针数组

#include <stdio.h>

int main()
{
	int (*pf[3])(int, int);	//函数指针数组
	return 0;
}

 ( * pf[3] ), []优先级更高, 所以pf, 是一个数组, 数组有3个元素

int (*)(int, int), (*) 表示这是一个指针

(int, int) 表示指针存储的是函数地址, 这个函数有两个int形参,

*前面的 int, 表示 返回类型是int

 

11.3 函数指针数组的使用

 

#include <stdio.h>

void menu()
{
	printf("**************************************\n");
	printf("************ 1.add 2.sub *************\n");
	printf("************ 3.mul 4.div *************\n");
	printf("************ 0.exit *************\n");
	printf("**************************************\n");
}

int add(int x, int y)
{
	return x + y;
}
int sub(int x, int y)
{
	return x - y;
}
int mul(int x, int y)
{
	return x * y;
}
int div(int x, int y)
{
	return x / y;
}

int main()
{	
	int x = 0;
	int y = 0;
	int n = 0;
	int res = 0;
	do
	{
		menu();
		printf("输入: ");
		scanf("%d", &n);
		if (n == 0)
		{
			break;
		}
		else if(n > 0 && n < 5)
		{
			printf("输入两个数: ");
			scanf("%d %d", &x, &y);
			int (*pf[5])(int, int) = { NULL, &add, &sub,&mul,&div };
			res = pf[n](x, y);
			printf("%d\n", res);
		}
		else
		{
			printf("error\n");
		}
		
	} while (n);
}

 这里的pf, 就是一个函数指针数组, 数组存放4个函数的地址

 

 

12. 存储函数指针数组的指针

 

12.1 什么是存储函数指针数组的指针

#include <stdio.h>
int main()
{
	int(*pf[5])(int, int); // 函数指针数组
	int(*(*ppf)[5])(int, int) = &pf; //存储函数指针数组的指针
}

 

12.1 如何理解

 

 int ( * ( *ppf ) [5] ) (int, int)

( *ppf ),表示ppf是一个指针

[5], 表示ppf存储的是一个数组, 数组有5个元素

 int(*)(int, int), 每一个元素的类型是函数指针

 

 

 13. 回调函数

 

13.1 什么是回调函数

#include <stdio.h>

void menu()
{
	printf("**************************************\n");
	printf("************ 1.add 2.sub *************\n");
	printf("************ 3.mul 4.div *************\n");
	printf("************ 0.exit *************\n");
	printf("**************************************\n");
}

int add(int x, int y)
{
	return x + y;
}
int sub(int x, int y)
{
	return x - y;
}
int mul(int x, int y)
{
	return x * y;
}
int div(int x, int y)
{
	return x / y;
}

void cal(int(*pf)(int,int))
{	
	int x = 0;
	int y = 0;
	printf("输入两个数: ");
	scanf("%d %d", &x, &y);
	int res = pf(x, y);
	printf("%d\n", res);
}

int main()
{
	int x = 0;
	int y = 0;
	int n = 0;
	int res = 0;
	do
	{
		menu();
		printf("输入: ");
		scanf("%d", &n);
		switch (n)
		{
		case 1:
			cal(add);
			break;

		case 2:
			cal(sub);
			break;

		case 3:
			cal(mul);
			break;

		case 4:
			cal(div);
			break;

		default:		
			break;

		}

	} while (n);
    return 0;
}

 回调函数是将一个函数的地址作为参数,传给另一个函数

这个例子中cal (add),为回调函数,将add函数的地址传给cal函数

 

标签:arr,int,地址,pa,printf,指针
From: https://www.cnblogs.com/xumu11291/p/17040376.html

相关文章

  • 空指针
     1.int*p=10就是给p变量存放地址为10值,这个是在定义的时候是给p变量赋地址值2.*p=10,就是给p变量的地址所指向的空间赋值为10,这个是p变量值所指向的地址空间赋值......
  • day2-双指针-977--59
     暴力解法      螺旋矩阵,边界条件有点多,要好好分析才可以  classSolution{public:vector<vector<int>>generateMatrix(intn){......
  • C语言指针统览
    前言本文对C语言指针和指针使用时的问题做一个概览性的总结,并对一些值得探讨的问题进行讨论。阅读本文,读者能达到统览C语言指针的目的。以下的讨论只针对32/64位机器。指针......
  • 算法入门(第二天)---双指针977,189
    977.有序数组的平方给你一个按非递减顺序排序的整数数组nums,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。输入:nums=[-4,-1,0,3,10]输出:[0,1,......
  • 指针知识点总结
    指针总结基础概念系统给虚拟内存的每个存储单元分配了一个编号,0x00000000-0xffffffff,这个编号是地址,指针就是地址内存数据的访问方式:(1)直接访问—按变量名存取变量......
  • c++ 常量指针和指针常量
    常量指针:const在*之前指针的地址是可以被再次赋值的(可以修改的)指针地址上面的值(变量)是不能被修改的常量指针的常量是不能被改变的指针常量:const在*之后指针的地......
  • cpp之智能指针
    1.介绍本文介绍智能指针的使用。智能指针是c++中管理资源的一种方式,用智能指针管理资源,不必担心资源泄露,将c++程序员从指针和内存管理中解脱出来,再者,这也是c++发展的趋......
  • Optional类的使用避免空指针
    一、Optional介绍Optional被定义为一个简单的容器,它可以保存类型T的值,其值可能是null或者不是null。在Java8之前一般某个函数应该返回非空对象但是偶尔却可能......
  • C语言指针大纲
    ......
  • 指针的引用
    前言我们在码代码的时候,会遇见在函数中修改传入变量的值,也就是所谓的传指针而不是传值。那么我们可不可以修改传入的指针变量的指针呢,也就是传指针的指针。正文当然可以......