C---指针(进级)

Posted L_add

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C---指针(进级)相关的知识,希望对你有一定的参考价值。

字符指针

指针类型是char*

int main()
{
	char ch = 'a';
	char* pc = &ch;
	char* p = "abcdef";
	//字符串中把首字符的地址存入p中
	printf("%c\\n", *p);//a
	printf("%s\\n", p);//abcdef
	return 0;
}
int main()
{
	char str1[] = "hello world";
	char str2[] = "hello world";
	char *str3 = "hello world";//常量字符串不能修改
	char *str4 = "hello world";
	if (str1 == str2)
		printf("Same\\n");
	else
		printf("Not Same\\n");
	if (str3 == str4)
		printf("Same\\n");
	else
		printf("Not Same\\n");
	return 0;
}

在这里插入图片描述

指针数组

存放指针的数组就是指针数组

int* arr[10]//整形指针的数组
char* arr[10]//一级字符指针的数组
char** arr[10]//二级字符指针的数组

数组指针

指向数组的指针叫数组指针

int main()
{
	int arr[10] = { 0 };
	int (*pa)[10] = &arr;//&arr数组名是整个数组,取出的是数组的地址
	int* pa[10];//指针数组,数组内的元素类型是int*
	return 0;
}

(pa)说明是指针变量,pa就是一个指向大小为10的数组的数组指针
[ ]的优先级高于,所以必须加上(),保证pa和*先结合

int main()
{
	int arr[10] = { 0 };
	int* p1 = arr;//数组首元素地址
	int(*p2)[10] = &arr;//数组的地址
	printf("%p\\n", p1);
	printf("%p\\n", p1+1);
	printf("------------------\\n");
	printf("%p\\n", p2);
	printf("%p\\n", p2+1);
	return 0;
}

在这里插入图片描述
&数组名
sizeof(数组名)
除此之外,所有遇到的数组名都是首元素地址

int main()
{
	int arr[5] = { 1, 2, 3, 4, 5 };
	int(*p)[5] = &arr;
	//*p <==> arr
	for (int i = 0; i < 5; i++)
		printf("%d ", (*p)[i]);
	//等价于:printf("%d ",*((*p)+i));
	//等价于printf("%d ", *((*p+0) + i)
	//等价于printf("%d ",p[0][i])

	return 0;
}
void Print1(int(*p)[5], int r, int c)
{
	for (int i = 0; i < r; i++)
	{
		for (int j = 0; j < c; j++)
			printf("%d ", (*(p + i) + j));
		printf("%\\n");
	}
	
}
void Print2(int* p, int c)
{}
int main()
{
	int arr[3][5] = { { 1, 2, 3, 4, 5 }, { 2, 3, 4, 5, 6 }, {3, 4, 5, 6, 7} };
	//二维数组传参,数组名是首元素的地址,二维数组的首元素是第一行
	//传过去就是第一行的地址
	Print1(arr, 3, 5);
	Print2(arr, 5);
	return 0;
}

在这里插入图片描述

int arr[5]五个元素的整形数组
int* p[10]整形指针数组,10个元素
int(*p1)[10]数组指针,指向的数组有10个元素,元素类型是int
int(*p2[10])[5]p2是存放数组指针的数组
void test(int arr[]){}//ok
void test(int arr[10]){}//ok
void test(int* arr){}//ok
int main()
{
	int arr[10] = { 0 };
	test(arr);
}
void test2(int* arr[20]){}//ok
void test2(int** arr){}//ok
int main()
{
	int* arr[20] = { 0 };
	test2(arr);
}
void test(int a[3][5]){}//ok
void test(int a[][]){}//NO!
void test(int a[][5]){}//ok
void test(int* a){}//No!
void test(int* a[5]){}//No!
void test(int (*a)[5]){}//ok
void test(int** a){}//No!
int main()
{
	int a[3][5] = { 0 };
	test3(a);
}

二级指针传参

void test(int** pr)
{
	printf("%d\\n", **pr);
}
int main()
{
	int n = 10;
	int* p = &n;
	int** pr = &p;
	int* arr[10];
	test(pr);
	test(&p);
	test(arr);
	return 0;
}

函数指针

指针

int Add(int x, int y)
{
	return x + y;
}
void test(char* str){}
int main()
{
	int(*p)(int,int) = &Add;//p是函数指针
	//(*p)指针,指向参数为(int,int),返回类型是int的函数
	void(*pf)(char*) = &test;
	//(*pf)是指针,指向参数为(char*),返回类型是void的函数
	int ret = (*p)(2, 3);//int ret = Add(2,3)
	return 0;
}
( * ( void (*)() ) 0 )();
//void(*)()-》函数指针类型
//调用0地址处的函数,该函数无参数,返回类型是void
void(*signal(int, void(*)(int)))(int);
//这是一个函数声明
//声明的函数叫signal,signal有两个参数,
//第一个参数类型是int,
//第二个参数类型是函数指针,该函数指针指向的函数的参数是int,返回类型是void
//signal函数的返回类型是一个函数指针,该函数指针指向的函数参数是Int,返回值是void
//简化
typedef void(*pfun_t)(int);//第一步
pfun_t signal(int, pfun_t);//第二步

函数指针数组

把函数的地址存到数组中,这个数组就叫做函数指针数组

int Add(int x, int y){}
int Sub(int x, int y){};
int main()
{
	int (*pfArr[2])(int,int) = { Add, Sub };
	//函数指针数组
	return 0;
}

指向函数指针数组的指针

指向函数指针数组的指针是一个指针,指针指向一个数组,数组的元素都是函数指针

int main()
{
	int(*p)(int, int);//函数指针
	int(*pf[4])(int, int);//函数指针数组
	int(*(*ppf)[4])(int, int) = &pf;
	//指向函数指针数组的指针
	return 0; 
}

回调函数

回调函数就是通过函数指针调用的函数。

void test1()//回调函数-》通过函数指针调用的函数
{
	printf("haha\\n");
}
void test2(void(*p)())
{
	p();
}
int main()
{
	test2(test1);
	return 0;
}

习题

1、

int main()
{
	int a[] = { 1, 2, 3, 4 };
	printf("%d\\n", sizeof(a));//16 - 数组名单独放在sizeof内部,计算的是数组总大小
	printf("%d\\n", sizeof(a + 0));//4/8 - 首元素地址+0,还是首元素地址
	printf("%d\\n", sizeof(*a));//4/8  *a - 数组a的首元素
	printf("%d\\n", sizeof(a + 1));//4/8  -第二个元素的地址
	printf("%d\\n", sizeof(a[1]));//4/8 - 数组的第二个元素
	printf("%d\\n", sizeof(&a));//4/8 - 数组的地址,是地址就是4/8个字节
	printf("%d\\n", sizeof(*&a));//16 &a->int(*p)[4] == sizeof(a)
	printf("%d\\n", sizeof(&a + 1));//4/8 //&a+1是地址,指向数组之后的空间
	printf("%d\\n", sizeof(&a[0]));//4/8 首元素的地址
	printf("%d\\n", sizeof(&a[0] + 1));//4/8 数组第二个元素的地址
	return 0;
}

2、

//字符数组
int main()
{
	char arr[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
	printf("%d\\n", sizeof(arr));//6 整个数组的大小
	printf("%d\\n", sizeof(arr + 0));//4/8 首元素的地址
	printf("%d\\n", sizeof(*arr));//1 *arr->数组首元素
	printf("%d\\n", sizeof(arr[1]));//1 arr[1]->数组第二个元素
	printf("%d\\n", sizeof(&arr));//4/8 数组的地址
	printf("%d\\n", sizeof(&arr + 1));//4/8 &arr+1跳过整个数组,还是地址
	printf("%d\\n", sizeof(&arr[0] + 1));//4/8 &arr[0]+1是第二个元素的地址
	
	printf("%d\\n", strlen(arr));//随机值 - 因为arr数组中没有\\0,就会在数组后继续找\\0
	printf("%d\\n", strlen(arr + 0));//随机值
	//printf("%d\\n", strlen(*arr));//error - *arr是'a',访问以a的ASCII值为地址的
	//printf("%d\\n", strlen(arr[1]));//error ,同理
	printf("%d\\n", strlen(&arr));//随机值
	printf("%d\\n", strlen(&arr + 1));//随机值-6
	printf("%d\\n", strlen(&arr[0] + 1));//随机值-1
	return 0;
}

3、

int main()
{
	char arr[] = "abcdef";//abcdef\\0 - 7
	printf("%d\\n", sizeof(arr));//7 计算数组的总大小
	printf("%d\\n", sizeof(arr + 0));//4/8 首元素地址
	printf("%d\\n", sizeof(*arr));//1 首元素
	printf("%d\\n", sizeof(arr[1]));//1 第二个元素
	printf("%d\\n", sizeof(&arr));// 4/8 &arr数组的地址
	printf("%d\\n", sizeof(&arr + 1));//4/8
	printf("%d\\n", sizeof(&arr[0] + 1));//4/8 &arr[0]+1是第二个元素的地址

	printf("%d\\n", strlen(arr));//6
	printf("%d\\n", strlen(arr + 0));//6
	printf("%d\\n", strlen(*arr));//error
	printf("%d\\n", strlen(arr[1]));//error
	printf以上是关于C---指针(进级)的主要内容,如果未能解决你的问题,请参考以下文章

第十八篇:Django进级

为啥在访问二级指针时出现分段错误错误? C语言

C++ - 指针和“智能指针”

使用 std::thread 函数 C++11 将指针作为参数传递

片段中的 EditText 上的空指针异常 [重复]

在C代码中将结构体变量作为参数传递效率忒低