嵌入式入门Day16

Day16

指针变量的使用

指针变量和字符串的关系

  1. " hello world":字符类型的数组,本质是一个地址
    520:整形类型
    'A':小数类型
    3.14:实数类型
  2. 字符串的本质是一个地址,可以使用一个指针变量存储该地址
    char *p = "hello world";
  3. 字符串常量存储在静态区的只读区域,如果对上面这个指针 p修改的话将会出现段错误

指针进阶

指针函数

  1. 指针函数本质上是一个函数,返回值为指针的函数就是指针函数
  2. 指针函数调用的结果是一个左值
  3. 指针函数返回的必须是一个生命周期比较长的空间的地址,不能返回局部空间的地址
    • 全局变量的空间
    • 静态变量的空间
    • 堆区申请的空间
    • 主调函数以地址传入的空间
  4. 指针函数实现了将被调函数中的内存传递给主调函数使用
  5. 定义格式:返回值类型 *函数名(参数列表){函数体;return 地址;}
c 复制代码
#include <stdio.h>


//值返回函数
int fun_1(int n)
{
	n += 10;
	return n;
}

//地址返回函数
int *fun_2()
{
	static int s = 66;
	return &s;
}

int main(int argc, const char *argv[])
{
	int num = 520;

	//调用功能函数1
	int res = fun_1(num); //值返回函数,结果为右值,只读
	
	printf("res = %d\n", res);
	//  fun_1(num) = 1314; 	//值返回函数不能作为左值 	报错
	
	int *ptr = fun_2();
	printf("*ptr = %d\n", *ptr);
	
	*fun_2() = 777; 		//指针函数的返回值是一个左值
	return 0;
}

函数指针

  1. 函数指针本质上是一个指针 ,用于指向函数的入口地址的指针
    任何函数在被调用时系统都会为其分配运行空间,有空间就会有地址,有地址就可以用指针变量来指向他。存储函数运行空间地址的指针变量称为函数指针变量
  2. 任何一个函数的函数名都是该函数对应的入口地址,是一个地址常量
  3. 函数指针定义格式:返回值类型 (* 变量名)(参数列表);
  4. 函数指针变量的用法:和函数名用法一致
c 复制代码
#include <stdio.h>

int sum(int m, int n)
{
	return m+n;
}

int judge(int m)
{
	return m%2 == 0 ? 1 : 0;
}

void sort(int *arr, int n)
{
	for (int i = 1; i < n; i++)
	{
		for (int j; j < n-i; j++)
		{
			if (arr[j] > arr[j+1])
			{
				int temp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = temp;
			}
		}
	}
	printf("排序成功\n");
}

int main(int argc, const char *argv[])
{
	//打印三个函数的地址
	printf("%p\t%p\t%p\t\n", sum, judge, sort);	
	
	//定义指针存储上面三个函数的入口地址
	int (*sum_ptr)(int,int) = sum;
	int (*judge_ptr)(int) = judge;
	void (*sort_ptr)(int *,int) = sort;
	
	//函数和函数指针都可以正常调用
	printf("和为: %d\n", sum(1,4));
	printf("和为: %d\n", sum_ptr(1,4));

	if (judge(56))
	{
		printf("是一个偶数\n");
	}else
	{
		printf("是一个奇数\n");
	}
	
	if (judge_ptr(56))
	{
		printf("是一个偶数\n");
	}else
	{
		printf("是一个奇数\n");
	}

	return 0;
}
  1. 使用函数指针完成函数回调(回调函数)
    函数回调:当调用某个函数时,不仅要向该函数中传递数据参数,也可以向该函数中传入一个功能
c 复制代码
#include <stdio.h>

int he(int m,int n)
{
	return m+n;
}

int cha(int m, int n)
{
	return m-n;
}

int ji(int m, int n)
{
	return m*n;
}

//使用传入的函数指针调用别的函数
void calculate(int m, int n,int (*x)(int,int))
{
	int res = x(m,n);
	printf("结果为:%d\n", res);
}

int main(int argc, const char *argv[])
{
	int num = 3, key = 6;

	calculate(num, key, he);
	calculate(num, key, cha);
	calculate(num, key, ji);

	return 0;
}

数组指针

  1. 数组指针的本质是一个指针 ,记录的是整个数组的地址
    数组指针针对的是整个数组,每偏移一个单位,内存地址就偏移了整个数组的大小
  2. 数组指针的定义格式:数据类型 (*指针名)[数组长度];
  3. 数组指针与一维数组的关系
    • 数组名是第一个元素的地址 ----> 变量的地址
    • 对一维数组名,再取地址,就得到了当前数组的地址(数组的地址)
c 复制代码
#include<stdio.h>

int main(int argc, const char *argv[])
{
    int arr[5] = {4,7,2,8,1};  	  //定义了一个长度为5的数组

    int *ptr = arr;     		  //普通元素的地址
    
    //定义一个指针变量,存储整个数组的地址
    int (*arr_ptr)[5] = NULL;  	 //定义一个数组指针
    arr_ptr = &arr;          	 //将数组指针指向整个数组    *arr_ptr = *&arr


    printf("sizeof(arr) = %ld\n", sizeof(arr));    //20


    printf("ptr = %p,arr=%p, &arr[0]=%p, &arr = %p,arr_ptr=%p\n",\
            ptr, arr, &arr[0], &arr, arr_ptr);

    printf("ptr+1 = %p,arr+1=%p, &arr[0]+1=%p, &arr+1 = %p, arr_ptr+1=%p\n",\
            ptr+1, arr+1, &arr[0]+1, &arr+1, arr_ptr+1);

    //使用数组指针访问元素
    printf("数组元素分别是:");
    for(int i=0; i<5; i++)
    {
        //printf("%d\t", (*arr_ptr)[i]);    // *arr_ptr ==> *(arr_ptr+0) ==> arr[0]
        printf("%d\t", arr_ptr[0][i]);    // *arr_ptr ==> *(arr_ptr+0) ==> arr[0]
    }
    return 0;
}
  1. 数组指针与二维数组的关系
    • 二维数组的数组名本质上是一个数组指针
    • 当数组指针与二维数组结合后,指针的偏移才有现实的意义
c 复制代码
#include<stdio.h>

int main(int argc, const char *argv[])
{
    int arr[2][3] = {{1,2,3}, {4,5,6}};    //定义一个二维整型数组
    //从元素的角度:定义了6个整形变量
    //从数组的角度:定义了两个一位数组
    
    //int *ptr = arr;        //?不可以进行  int *ptr=arr[0]
    
    int (*arr_ptr)[3] = arr;     //定义数组指针存储二维数组名


    printf("&arr[0][0]=%p, arr[0]=%p, arr=%p, arr_ptr=%p\n",\
            &arr[0][0], arr[0], arr, arr_ptr);

    printf("&arr[0][0]+1=%p, arr[0]+1=%p, arr+1=%p, arr_ptr+1=%p\n",\
            &arr[0][0]+1, arr[0]+1, arr+1, arr_ptr+1);

    //使用数组指针访问元素
    //arr_ptr 表示的是第一行的整体地址  
    
    //arr_ptr+i :表示任意一行的整体地址 
    
    //*(arr_ptr+i) :表示任意一行的第一个元素的地址  --> arr_ptr[i]
    
    //*(arr_ptr+i) +j :表示的是下标为i和j的元素的地址 --> arr_ptr[i]+j
    
    // *(*(arr_ptr+i)+j):表示任意一个元素   --> *(arr_ptr[i]+j)  -->arr_ptr[i][j]
    
    printf("数组元素分别是:\n");
    for(int i=0; i<2; i++)
    {
        for(int j=0; j<3; j++)
        {
            //printf("%d\t", arr_ptr[i][j]);
            printf("%d\t", *(*(arr_ptr+i)+j));
        }
        printf("\n");
    }
    
    return 0;
}

指针数组

  1. 指针数组本质上是一个数组,但是每个元素都是一个指针变量
  2. 定义格式:数据类型 *数组名 [数组长度]

函数指针数组

  1. 函数指针数组本质上是一个数组,数组中的每个元素都是一个函数指针变量,都可以存储函数入口的地址
  2. 能够实现对函数的批量调用
  3. 定义格式:返回值类型 (* 数组名[数组长度])(形参列表)

二级指针

  1. 每个指针变量都占有内存空间,有空间就有地址,就可以使用指针存储他的地址
  2. 存储一级指针变量的地址的指针变量就是二级指针变量
    一级指针变量的地址为二级指针
  3. 定义格式:数据类型 **指针名
  4. 二级指针变量的值为:一级指针变量的地址
    二级指针指向的内存空间中的值是一级指针(也就是变量的地址)---> *二级指针变量
    二级指针取值两次是变量的值 ---> **二级指针变量
  5. 二级指针变量常用于函数参数为主程序中的一级指针变量进行赋值

万能指针

  1. 万能指针就是可以接收任意地址的指针变量
  2. 定义格式:void *指针名
  3. 由于没有任何类型的限制,导致该指针变量可以接收任意类型的地址
  4. 对于万能指而言不能直接进行*运算
相关推荐
程序员与背包客_CoderZ23 分钟前
C++设计模式——Singleton单例模式
c语言·开发语言·c++·单例模式·设计模式
小猿_0030 分钟前
C语言蓝桥杯组题目
c语言·开发语言·蓝桥杯
丶Darling.33 分钟前
MIT 6.S081 | 操作系统 | Lab1: Xv6 and Unix utilities
linux·服务器·c语言·操作系统·unix·lab·mit 6.s081
Moring.1 小时前
平面点排序(结构体专题)
c语言
赔罪2 小时前
C 语言变量说明符
c语言·开发语言·c++·学习·算法·objective-c
CYRUS STUDIO2 小时前
编译 LLVM 源码,使用 Clion 调试 clang
c语言·c++·visual studio·clang·ndk·llvm·clion
St_Ludwig2 小时前
C语言小撰特殊篇-assert断言函数
c语言·c++·后端·算法
style-h3 小时前
C语言——数组基本知识(一)
c语言·数据结构·算法
芥末虾3 小时前
【优选算法】KMP模式匹配算法 {算法介绍;算法原理:核心原理,如何求next数组;代码实现}
c语言·c++·算法·kmp·字符串模式匹配