指针进阶(一)

文章详细介绍了指针的概念,包括指针作为变量存储地址、指针的固定大小、指针类型与运算,特别是字符指针的使用。同时,讨论了指针在数组和字符串中的应用,如常量字符串的存储以及数组和指针数组的区别。此外,还阐述了一级指针和二级指针在函数参数传递中的作用,以及函数指针的使用和声明。
摘要由CSDN通过智能技术生成
1. 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。
2. 指针的大小是固定的 4/8 个字节( 32 位平台 /64 位平台)。
3. 指针是有类型,指针的类型决定了指针的 +- 整数的步长,指针解引用操作的时候的权限。
4. 指针的运算。

字符指针

指针类型为字符指针——char*

一般使用

int main()
{
    char ch="w";
    char *pc=&ch;
    *pc='w';
    return 0;
}

还有一种使用方式如下:

int main(){
  const char*pstr="hello bit.";
  printf("%s\n",pstr);
  return 0;
}
hello bit放到字符指针 pstr 里了,但是/本质是把字符串 hello bit. 首字符的地址放到了pstr中。
面试题
#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;
}

运行结果:

str3 str4 指向的是一个同一个常量字符串。 C/C++ 会把常量字符串存储到单独的一个内存区域,当几个指针。 指向同一个字符串的时候,他们实际会指向同一块内存。
但是用相同的常量字符串去初始化 ,不同的数组的时候就会开辟出不同的内存块。所以 str1 str2 不同, str3 str4 不同。

指针数组

整形指针的数组  int* arr1[10]

一级字符指针的数组

二级字符指针的数组


数组指针

 定义

int *p1[10];

int (*p1)[10];

第二个为数组指针

这是一个指针变量,指向的是一个大小为10个整形的数组。所以p是一个指针,指向一个数组,交数组指针。

【】的优先级高于*号,所以需要加上();

int (*p)[10]=&arr   整个数组的地址

&数组名与数组名

arr是数组名,数组名表示数组首元素的地址;

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

+40 =10个数*10

通过二组代码的对比

&arr表示的是数组的地址,而不是数组首元素的地址。

&arr的类型是 int(*)[10] ,是一种数组指针的类型

数据地址+1,跳过了整个数组的大小,所以&arr+1相对于&arr的差值是40;

 数组指针的使用

数组指针指向的是数组,那数组指针中存放的应该是数组的地址

void printf2(int(*p)[4],int r,int c){
	int i = 0;
	for ( i = 0; i < r; i++)
	{
		int j = 0;
		for ( j = 0; j  < c; j++)
		{
			//printf("%d ", (*(p + i))[j]);
			printf("%d ", p[i][j]);
		}
		printf("\n");
	}
}
int main() {
	int arr[3][4] = { {1,2,3,4},{2,3,4,5},{3,4,5,6} };
	//printf1(arr, 3, 4);
	printf2(arr,3,4);
	return 0;
}

数组和数组指针的含义题

int arr[5];
int *parr1[10];
int (*parr2)[10];
int (*parr3[10])[5];

 整形数组,数组是5个元素

指针数组,数组10个元素,每个元素是int*类型的

parr2是指针数组,该指针指向一个数组,数组是10个元素,每个元素是int类型的

parr3是数组,数组有10个元素,数组的每个元素的类型是:int(*)[5]的数组指针类型


 数组参数、指针参数

 一维数组传参

#include <stdio.h>
void test ( int arr []) //ok? 数组传参,数组接收!
{}
void test ( int arr [ 10 ]) //ok? 数组传参,数组接收!
{}
void test ( int * arr ) //ok? 数组传参,指针接收!
{}
void test2 ( int * arr [ 20 ]) //ok?
{}
void test2 ( int ** arr ) //ok?  形参\首元素的地址是一级指针的地址,所以这里是二级指针是对的
{}
int main ()
{
int arr [ 10 ] = { 0 };
int * arr2 [ 20 ] = { 0 };
test ( arr );
test2 ( arr2 );
}

 二维数组传参

void test ( int arr [ 3 ][ 5 ]) //ok
{}
void test ( int arr [][]) //ok
{}
void test ( int arr [][ 5 ]) //ok
{}
// 总结:二维数组传参,函数形参的设计只能省略第一个 [] 的数字。
// 因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
// 这样才方便运算。
void test ( int * arr ) //ok
{}
void test ( int* arr [ 5 ]) //ok
{}
void test ( int ( * arr )[ 5 ]) //ok
{}
void test ( int ** arr ) //ok
{}
int main ()
{
int arr [ 3 ][ 5 ] = { 0 };
test ( arr );
}
void test ( int arr [ 3 ][ 5 ]) //ok
{}
void test ( int arr [][]) //ok
{}
void test ( int arr [][ 5 ]) //ok
{}
// 总结:二维数组传参,函数形参的设计只能省略第一个 [] 的数字。
// 因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
// 这样才方便运算。
//行可以省略,但是列不可以
void test ( int * arr ) //ok ? NO!!!二维数组,这是一维数组
{}
void test ( int* arr [ 5 ]) //ok ? 完全不对,这是个指针数组
{}
void test ( int ( * arr )[ 5 ]) //ok ? 可行!
{}
void test ( int ** arr ) //ok ? NO!二级指针是用来接收一级指针的
{}
int main ()
{
int arr [ 3 ][ 5 ] = { 0 };
test ( arr );
}

 一级指针传参

#include <stdio.h>
void print(int *p, int sz)
{
 int i = 0;
 for(i=0; i<sz; i++)
 {
 printf("%d\n", *(p+i));
 }
}
int main()
{
 int arr[10] = {1,2,3,4,5,6,7,8,9};
 int *p = arr;
 int sz = sizeof(arr)/sizeof(arr[0]);
 //一级指针p,传给函数
 print(p, sz);
 return 0;
}

当一个函数的参数部分为一级指针的时候,函数能接收什么参数?void test(int*p){

}

 可以接收:

int a=10;

int*p =&a;

int arr[10];

一个一维数组的数组名

一个指针地址

一个整型变量的地址


二级指针传参

#include <stdio.h>
void test(int** ptr)
{
 printf("num = %d\n", **ptr); 
}
int main()
{
 int n = 10;
 int*p = &n;
 int **pp = &p;
 test(pp);
 test(&p);
 return 0;
}

传过去是一级指针就用一级指针接收,二级指针就用二级指针接收;


当函数的参数为二级指针的时候,可以接收什么参数?

 二级指针变量、一级指针的变量地址、指针数组的数组名

void test(){
}

int **ptr;
int*pp;
int* arr[10];
test(ptr);
test(&pp);
test(arr);

函数指针

#include <stdio.h>
int ADD(int x,int y)
{
	return x + y;
}
int main()
{
	//int arr[10];
	//int(*pa)[10] = &arr;
	int(*pf)(int, int) = &ADD;
	int ret=(*pf)(2,3);
	printf("%d\n", ret);
	//pf是一个存放函数地址的指针变量-函数指针
	return 0;
}

通过指针调用函数ADD,得到5

int ret=(*pf)(2,3);   其实int ret=pf(2,3);  如果加*好理解,但是必须加括号

int main(){
(*(void(*)())0)();
return 0;
}

这个代码是一次函数调用,调用0地址处的一个函数;

首先将0强制转换为类型为void(*)()的函数指针,然后调用0地址处的函数;

void(*signal(int,void(*)(int)))(int);

该代码是一次函数的声明,声明的函数名为signal

signal函数的参数有两个,第一个int类型,第二个是函数指针类型,该函数指针能够指向那个函数的参数是int

返回值类型是void

代码优化

typedef void(*pf_t)(int):

pf_t signal(int,pf_t)

类型的重命名

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tech行者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值