C语言基础指针*

目录

一、字符指针

1.const作用简单介绍

二、指针数组、数组指针

1.指针数组

2.数组指针

3.数组指针的使用

 3.1数组指针传参

四、数组传参

4.1一维数组传参

4.2二维数组传参

五、函数指针

 5.1函数指针存储

5.2函数指针调用

5.3练习


指针就是一个变量,用来存放地址,一个地址唯一标识一块内存空间。

指针大小4/8字节(32位平台/64位平台)

指针是有类型的,其类型决定了指针±整数时的步长,和对其解引用‘*’时的权限(能够操作几个字节)

一、字符指针

char arr='d';

char*p=&arr;(取出arr地址放入到p中)

此时*p=='d';

*p='w';(把对应地址存放变量d赋值为w)

其余类型指针情况类似

一个特殊情况

int main()
{
  char *str="hello world";
  printf("%s\n",str);
  return 0;
}

此时打印的结果是hello world,是把hello world放入到str指针变量里了吗?显然不是

"hello world"为常量字符串,本质是把字符串的首地址放入到了str中。

一个练习

#include 
int main()
{
    char s1[] = "hello";
    char s2[] = "hello";
    const char *s3 = "hello";
    const char *s4 = "hello";
    if(s1 ==s2)
 printf("s1等于s2\n");
    else
 printf("s1不等于s2\n");
       
    if(s3 ==s4)
 printf("s3等于s4\n");
    else
 printf("s3不等于s4\n");
       
    return 0; 
}

 结果为s1不等于s2

            s3等于s4

        原因是s3和s4指向的是同一个常量字符串,C/C++会把常量字符串存储单独存储到一个内存区域,当几个指针指向同一个字符串时,实际上会指向同一内存。但是用相同的常量字符串初始化不同数组时就会开辟不同的内存块。

1.const作用简单介绍

const修饰的常变量(本质还是变量)不能用于arr[中];

const在*同一侧时起的作用都是相同的

const char*p;char const*p,此时*p不能赋值改变

char* const p,此时p不能被赋值改变

二、指针数组、数组指针

1.指针数组

用于存放指针的数组

int *arr[5];//存放五个int类型的指针数组

int **arr[5];(二级指针)//存放五个指针指向int*的数组

数组名表示的是数组首元素地址,以下两种情况除外

此时&arr为取出整个数组地址,(但是&arr==arr);sizeof(arr)中的arr为整个数组字节大小

2.数组指针

指向数组的指针,用于存放整个数组的地址

int(*p)[5];//p为指针,指向含有五个元素的整型数组。

int*p[5];

[]的优先级高于*,如果不加(),p会和[5]先结合成一个有五个元素的数组

下面举个例子进行练习

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

 C语言基础指针*_第1张图片

 可以看到arr和&arr的输出是相同的,但是当二者都加1后结果却不相同了,原因就在于,&arr取出的是整个数组地址,加1后跳过的是整个数组

C语言基础指针*_第2张图片

3.数组指针的使用

#include
int main()
{

int arr[5]={1,2,5,4,7};
int(*p)[5]=&arr;
return 0;
}

 3.1数组指针传参

二维数组传参是传的是第一行元素的地址,行数可以不设置,但列一定要设置

#include 
void arr1(int arr[][4], int row, int col) 
{
    int i = 0;
    for(i=0; i

在我们了解以上知识后我们来看看这个int(*arr[8])[6]

对其进行分析arr和[8]相结合,组成一个数组,有8个元素,每个元素为指针类型,指针指向含有6个int型元素的数组,每个元素类型为int(*)[6],存放数组指针的数组。

四、数组传参

4.1一维数组传参

一维数组传参传的是首元素地址,数组存放是连续的

#include 
void test(int arr[])//F or T?
{}
void test1(int arr[10])//F or T?[]中的数字没有意义,仅仅是为了方便初学者学习理解,并不会创建一个形参数组
{}
void test2(int *arr)//F or T?
{}
void test3(int *arr[20])//F or T?
{}
void test4(int **arr)//F or T?
{}
int main()
{
 int arr[10] = {0};
 int *arr2[20]={0};//传地址二级指针(地址的地址),每个元素为int*类型
 test(arr);
 test1(arr);
 test2(arr);
 test3(arr2);
 test4(arr2);
}

 答案:T T T F T

4.2二维数组传参

二维数组传的是第一行元素的地址,二维数组本质上也是连续存放的,第一行后面跟着第二行。。。。。

void test(int arr[3][5])// T
{}
void test(int arr[][])//  F
{}
void test(int arr[][5])//  T 行可以省略,列不能省略
{}
//二维数组传参,函数形参的设计只能省略第一个[]的数字。
void test(int *arr)// F  
{}
void test(int* arr[5])// F 是指针数组
{}
void test(int (*arr)[5])// T  数组指针
{}
void test(int **arr)//  F  二级指针
{}
int main()
{
 int arr[3][5] = {0};
 test(arr);
}

五、函数指针

#include 
void test()
{
 printf("C++\n");
}


int main()
{
 printf("%p\n", test);
 printf("%p\n", &test);//和数组不同,这两种都是函数地址
 return 0;
}

 5.1函数指针存储

int Add(int x,int y)
{

  return 0;

}

 函数返回类型为int,其参数为两个int元素,int (*pp) (int,int)=Add;pp就是函数指针变量

5.2函数指针调用

pp中存放的是Add地址,进行调用对其解引用*即可,(*pp)(num1,num2);

注意不要写成*pp(num1,num2)这种形式

但其实不对其解引用直接pp(num1,num2);也可以正常使用。*在此处并没有意义

写成*pp(1,2)这种形式就变成了*3,就会出现问题。

5.3练习

//码1 
(*(void (*)())0)();
//码2
void (*evial(int , void(*)(int)))(int);

这两串代码是什么意思?

例1

(  *(  void (*)  (  )  )0  )(); //假设此处0为一个地址
void(*)()//函数指针类型,指向的函数为无参返回值为void型
(void(*)())0//对0进行强制类型转换,转换为函数指针类型,意味着0地址处放一个函数
*(  void (*)  (  )  )0 //对其进行解引用
(  *(  void (*)  (  )  )0  )()//解引用后对其传参

 

例2

void (  *eva(  int , void(*)(int)  )  )(int);

void(*)(int)和int为eva( , )的两个参数的类型

eva的返回值类型为void(*)(int)

其形式比较复杂,我们可以通过typedef对其函数指针类型进行重命名

typedef void(*pp)(int)//将函数指针类型void(*)(int)重命名为pp
typedef void(*)(int) pp;//这种形式是错误的
pp eva(int,pp)

 

后续会更新函数指针数组,指向函数指针数组的指针和回调函数qsort模拟实现。

感谢各位的阅读。

你可能感兴趣的:(c语言,开发语言,c++)