c语言指针的进阶

指针的进阶



前言

区别于之前指针的初步了解,增添了更多内容


一、字符指针

在指针的类型中有一种类型为字符指针char*;

一般使用:

int main()
{
   
  char ch='w';
  char *pc=&ch;
  *pc='w';
  return 0;
}
int main()
{
   
  char* pstr = "hello bit.";
  printf("%s\n",pstr);
  return 0;
}

代码 char* pstr = “hello bit.”;错误理解为字符串hello bit 存入字符指针pstr中
本质为字符串hello bit 首字符的地址放入pstr中

例如:下面代码的执行结果为( )

#include <stdio.h>
int main()
{
   
  char str1[] = "hello bit.";
  char str2[] = "hello bit.";
  char *str3 = "hello bit.";
  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; 
}

A.str1 and str2 are same str3 and str4 are same
B.str1 and str2 are same str3 and str4 are not same
C.str1 and str2 are not same str3 and str4 are same
D.str1 and str2 are not same str3 and str4 are not same

答案为(C)

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

注意:字符常量区是只读的,str3,str4指向相同的字符串只需要保存一份就够了。(减少成本)

二、指针数组

指针数组是一个存放指针的数组,归根结底是个数组。

int * char arr1[10]

分析:中括号优先级高,所以为一个数组。数组就一定有元素,所以数组内存储int*类型数据。称为整形指针数组

char * arr2[10]

同理,一个存储 char* 的数组,称为一级字符指针数组。
内容可以指向1.某种字符2.指向某个字符串

char ** arr3[10]

同理,一个存储char**的数组,称为二级字符指针数组。
内容可以指向在后面详解

三、数组指针

1.定义及理解

首先数组指针是指针。

我们知道:
整形指针:int * pint;能够指向整形数据的指针。
浮点型指针:float * pf;能够指向浮点型数据的指针。
那么,数组指针为能够指向数组的指针

1. p1,p2分别是什么?

int * p1[10];
int*p2)[10];

分析:
int * p1[10];为整形指针数组,数组内保存指针
int ( * p2)[10];为数组指针。p2先和*结合,说明p2是一个指针变量,然后指针指向一个大小为10个整形的数组

2.

int main()
{
   
  int(*p1)[10]=NULL;
  int(*p2)[11]=NULL;
  p1=p2;
}

编译出现告警:
在这里插入图片描述
首先前两行一定正确属于变量定义,指针指向空。根据告警显示数组是p1=p2出错,因为p1和p2指向的数组不同,因此数组的下标也是数组的一部分。

3.
下面写法是否正确?

int main()
{
   
  int(*p1)[10]=NULL;
  int a[10];
  p1 = a;
}

答案:错误。
分析: p1 = a ; 其中 a 做右值不代表整个数组而是首元素地址,所以 a 实际上是int * 型,而 p1 为 int(*)[10]型。右侧是一个整形指针,左侧是一个是指向整形数组的指针,因此他们类型不同。正确做法应该改成,p1=&a.数组的地址就是数组指针类型。

2.&数组名VS数组名

通过下列代码完成理解
代码如下:

int main()
{
   
  int arr[10];
  printf("%p\n",arr);
  printf("%p\n",&arr);
  printf("%p\n",arr+1);
  printf("%p\n",&arr+1);
}

运行结果为:
在这里插入图片描述
可见数组名和&数组名打印地址一样,但实际意义不同。
因为对指针加一表示对其所指数据类型的大小加一,很显然arr+1相对于arr是4,&arr+1相对于&arr是40。

由此得出:arr是数组名,数组名表示首元素地址(大部分情况)
&arr表示数组的地址,而不是数组首元素地址

补充:arr+1等价于&arr[1],*(arr+1)等价于arr[1],

3.数组指针的使用

数组指针指向的是数组,那么数组指针中存放的就是数组的地址

深入理解,如下所示并理解,

int main()
{
   
int a[10]={
   1,2,3,4,5};
int(*p)[10]=&a;
printf("%p",p[1]);
printf("%p",p[0][1]);
}

一、p[1]等价于*(p+1)也就是p指向下一个元素再进行解引用,因为p指向a,所以*(p+1)表示越过整个a数组再进行解引用,是一种越界行为。
二、p[0][1] 中的 p[0] 等价于 *(p+0) 整个数组相当于 数组名也就是首元素地址就是a,p[0][1] 等价于 *(*p+0)+1 也就是a[1]。

四、数组参数、指针参数

只要传参就要发生拷贝。数组是先降维再拷贝(降维成指针,指向其内部元素类型的指针。在数组传参时传的是数组名相当于是首元素地址),拷贝的仍是指针;指针传参会发生形参实例化,发生临时拷贝。

1.一维数组传参

#include <stdio.h>
#include <stdio.h>
void test(int arr[])//ok? yes
{
   }
void test(int arr[10])//ok?yes
{
   }
void test(int *arr)//ok?yes
{
   }
void test2(int *arr[20])//ok?yes
{
   }
void test2(int **arr)//ok?yes
{
   }
int main()
{
   
 int arr[10] = {
   0};
 int *arr2[20] = {
   0};
 test(arr);
 test2(arr2);
}

以上几种方式都是正确的

2.二维数组传参

void test(int arr[3][5])//ok?yes
{
   }
void test(int arr[][])//ok?no,二位数字下标不能省略,数组类型不明确
{
   }
void test(int arr[][5])//ok?yes
{
   }
void test(int *arr)//ok?no,传入的是数组指针
{
   }
void test(int* arr[5])//ok?no,是指针数组
{
   }
void test(int (*arr)[5])//ok?yes,将为成二级指针
{
   }
void test(int **arr)//ok?no,是等价于int *arr[5],是指针数组
{
   }
int main()
{
   
 int arr[3][5] = {
   0};
 test(arr);
}

3.一级指针传参

#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;
}

问题:第7行的p和第13行的p一样吗?
答案:不一样
分析:指针传参没有拷贝数组,但是会有指针临时变量,只是内容一样指向空间一样。

下列函数的参数为一级指针时能接收什么参数?

void test1(int *p)
{
   }
//test1函数能接收什么参数?
void t
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值