1 指针基础 怎么获得变量地址

1 如何产生一个指针变量 ——>类型* 标识符; int* p1; char* p2; double* p3; //不同类型的基本指针占用内存是一样的都是4个字节(32位)/8个字节(64位),都是存的地址

2 数组名是数组首地址但不是普通指针 ——>数组名绑定的一段内存可以影视转化为指针 int array[4] = { 1,2,3,4}; printf("array:%zd\n", sizeof(array));//打印16,整个数组的大小 printf("array:%p\tarray[0]:%p", array, &array[0]);//值一样,内容不一样

3 intp1;未初始化是野指针 p1=NULL;变成空指针。 NULL-->(void)0 把0强制转化地址 一般定义指针 int*p=NULL;

4 指针取值运算 int num=666; int*P=# //*指针变量 ,指针变量[0]; printf("%d\t%d\t%d\n", num, *pnum, pnum[0]);//都打印666 *pume=888; printf("%d\t%d\t%d\n", num, pnum, pnum[0]);//都打印888 //操作指针变量pume就相当于操作num,任意修改一个其他都会跟着变

5 指针偏移——>移动数据位 //p+n或者p-n是移动数据位 //int* p 要明白指针类型 //指针的类型:int* -->去掉变量名 //指针的所指向类型:int-->操作的数据的类型-->去掉变量名和*号(基类型) //知道操作的数据类型就知道偏移多少 printf("p1=%p\n", p1); int p1=0000000000000000 printf("p2=%p\n", p2); char p2=0000000000000000 printf("p3=%p\n", p3); double p3=0000000000000000 //+1,偏移一个数据位
printf("p1=%p\n", p1+1); int p1=0000000000000004 printf("p2=%p\n", p2+1); char p2=0000000000000001 printf("p3=%p\n", p3+1); double p3=0000000000000008

printf("array=%p\n", array); array=000000A8A24FF4C8 printf("array=%p\n", array+1); array=000000A8A24FF4CC //差4

int(*p)[3] = NULL;
printf("p=%p\n", p ); //操作的是int[3] printf("p=%p\n", p + 1); //int[3]——>偏移一个数组12个字节

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 2 const与指针变量 const后面不能被修改,把变量变成了常属性。

1.以下两种没区别 const int cnum1 = 0; int const cnum2 = 0;

2.在前面,指针指向内容不可以修改——>修饰1 //以下两种没区别 //const描述的是指针所指向的内容 const int p1 = &cnum1; int const* p2 = &cnum1; int data = 0; *p1=666;(不行) p1 = &data; p1 = p2;(可以)

3在后面,指针不可以修改——>修饰2 //让指针变量指向的地址固定 int const p3 = &data; //const修饰的是p3 不可修改 p3 = p2; (不行) p2 = p3;(可以)

4const int* const p4 = &data; //都不能被修改

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

3 二级指针与多级指针 因为指针变量也有地址,也可以用指针来存放 类似与套娃 int num = 0; int* p1 = # int** p2 = &p1; int*** p3 = &p2;

num = 999; printf("%d\n", ***p3); printf("%d\n", p3[0][0][0]);//这两个也一样都打印999 1 2 3 4 5 6 7 8 9 10 4 指针操作一维数组 指针指向数组首地址,直接当数组名去用

1 int array[4] = { 1,2,3,4 }; int* p = array; //p = &array[0]; for (int i = 0; i < 4; i++) { printf("%d\t", p[i]); //推荐用法 //printf("%d\t", *(p + i)); //printf("%d\t", (p + i)[0]); }

//下面用法不推荐,但是要能看懂
//改变指针指向,指针偏移到数组之后,任意越界用起来危险
while (p != array + 4)

{ printf("%d\t", p++[0]); } printf("\n");

2 负下标,不用首地址做初始化

int data[10] = { 1,2,3,4,5,6,7,8,9,10 }; int* pp = &data[5]; printf("%d\n", pp[0]); for (int i = -4; i < 0; i++) { printf("%d\t", pp[i]); } printf("\n");

3 函数传参,传输组名等效于传一级指针(数字类必须还要传长度) 在 C 语言中,数组作为函数参数时,实际上是传递数组的首地址,而不是整个数组。 因此,函数内部无法直接获取数组的长度。这就是为什么我们需要额外传递数组的长度(元素数量)的原因

void print_array(int array[], int arrayNum)

{ for (int i = 0; i < arrayNum; i++) { printf("%d\t", array[i]); } printf("\n"); } void print_array_2(int *array, int arrayNum) { for (int i = 0; i < arrayNum; i++) { printf("%d\t", array[i]); } printf("\n"); }

4 传字符串一定要写const,C语言里可能没有影响,c++有影响(养成好习惯) int my_strlen(const char* str) { int count = 0; while (str[count] != '\0') count++; return count; }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 5 指针操控二维数组 1 一级指针操作二维数组——>列转换为序号 void test_one() { int array[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 }; int* p = &array[0][0]; for (int i = 0; i < 3; i++) { for (int j = 0; j < 4; j++) { //行列转换为序号 printf("%d\t", p[i * 4 + j]); } printf("\n"); }

2 数组指针操作

void test_two()

{ int array[3][4] = { 1,2,3,4,5,6,7,8,9,10,12 }; //二维数组名偏移的一行 printf("array:%p\n", array); printf("array+1:%p\n", array+1); //16 //二维数组名+一个下标 转换为一个一级指针 printf("array[0]:%p\n", array[0]); printf("a rray[0]+1:%p\n", array[0]+1); //4;

2.1//推荐用法!!! 
//数组指针操作二维数组(直接当数组名)
int(*p)[4] = array;
for (int i = 0; i < 3; i++) 
{
	for (int j = 0; j < 4; j++) 
	{
		printf("%d\t", p[i][j]);
	}
	printf("\n");
}



以下是多种写法,用A换元思想(书本上出现要认识)
2.2 for (int i = 0; i < 3; i++)
{
	for (int j = 0; j < 4; j++)
	{
		printf("%d\t", *(*(p+i)+j));
		//p[i]==>A  A[j]==>*(A+j)
		//p[i]==>*(p+i)==>A
	}
	printf("\n");
}

2.3		printf("%d\t", *(p[i] + j));
		//p[i]==>A  A[j]==>*(A+j)
		//p[i]==>A
	
2.4		printf("%d\t", ((p + i)[0] + j)[0]);
		//p[i]==>A  A[j]==>*(A+j)==>(A+j)[0]
		//p[i]==>(p+i)[0]==>A

2.5		printf("%d\t", (p[i] + j)[0]);
		//p[i]==>A  A[j]==>*(A+j)==>(A+j)[0]
		//p[i]==>(p+i)[0]==>A

3 函数传参 void print_array(int(*p)[4], int row, int cols) { for (int i = 0; i < row; i++) { for (int j = 0; j < cols; j++) { printf("%d\t", p[i][j]); } printf("\n"); } } void test_three() { int array[3][4] = { 1,2,3,4,5,65,7,8,9,0,19,12 }; print_array(array, 3, 4); }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 6 万能指针 #include <stdio.h> #include <stdlib.h> int main() {

//万能指针 void* p = NULL; int num = 999; p = &num;

//万能指针不能*p直接访问 //要做目标数据类型的强制类型转换 printf("%d\n", *(int *)p); double dNum = 8.98; p = &dNum; printf("%.2lf\n", (double)p);

return 0;

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 7 指针函数 #include <stdio.h> #include <stdlib.h>

一. 传指针问题

1 //值传递 void modify_one(int a) //int a=实参 { a = 100; } //没有返回值,打印出来还是0

//址传递(函数不需要返回值就可以修改值)

2 //修改实参的值 ,传入实参的地址,修改是地址 void modify_two(int p) //int* p=实参 { *p = 100; }

3 //(为什么传二级指针)修改指针指向num指向g_num,用二级指针接收指针的地址 int g_num = 999; void modify_point(int** p) //int** p=实参 { p = &g_num; } //—————————————————————————————————————————————— int main(){ 1 int num = 0; modify_one(num); printf("%d\n", num); //——————————————————————————————————————————————
2 modify_two(&num); printf("%d\n", num); //——————————————————————————————————————————————
3 int
p = &num; modify_point(&p);//传入的指针变量 printf("%d\n", p[0]); }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 二. 返回指针问题

1 //C语言不允许返回局部变量的地址(不安全的) //内存会回收,变量地址给其他不知道的东西了 //warning C4172: 返回局部变量或临时变量的地址: num int* get_num() { int num = 99999; return &num;(不行) }

2 //需要学会区分什么叫做局部变量的地址 int* get_num_one(int* p) { return p;(可以)——>因为在主函数里调用时,变量一直到结束时都是有效的 }

3 //可以返回堆区内存的地址(下章说)

4 //返回一个数组的函数(返回数组首地址就可以了) int array[3] = { 1,2,3 }; int* get_array() { return array; }

int main() { 1 int* pp = get_num(); printf("%d\n", *pp); printf("%d\n", *pp); //——————————————————————————————————————————————
2 get_num_one(p);//函数返回指针后还可以的继续操作 //p[0]; get_num_one(p)[0]; //*p=199; get_num_one(p) = 199; printf("%d\n", g_num); //—————————————————————————————————————————————— 4 int parray = get_array(); for (int i = 0; i < 3; i++) { printf("%d\n", parray[i]); } printf("\n"); return 0; }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47

!!!这里先看一下指针函数和函数指针的区别,下篇会将到函数指针,容易弄混!!!