嵌入式C语言学习笔记 - 函数、数组、指针

函数

数据类型  函数名(数据类型 形参1,数据类型,形参2)

函数的优势:提高代码的复用性,提高代码的可维护性

函数使用的三个步骤:函数定义、函数声明、函数调用

函数与函数之间是平级的关系;

定义的函数需要在使用前声明;

  1. 定义这个函数的主要实现什么事情(函数体-函数名);
  2. 函数实现这个功能,需要什么才能完成(是否需要形参);
  3. 函数功能实现了,调用处是否需要继续使用(是否需要返回,返回内容数据类型);

【注意事项】

  • return下面不要写代码,永远执行不到,属于无效代码;
  • 函数返回值类型为void,则不需要return;如果书写了,则在return 为空;

示例(计算两个数据的求和):

//求两个数据之和
int add(int a,int b)
{
	return a+b;
}
//求两个数据之差
int sub(int a,int b)
{
	return a-b;
}
//求两个数据的乘法
int mul(int a,int b)
{
	return a*b;
}
//求两个数据的除法
int div(int a,int b)
{
	return a/b;
}

数组

数组的在嵌入式中可以理解为一段连续的内存,内存中存放的数据内容;

是一种容器,可以用来储存同种数据类型的多个值;

数组是一个连续空间,数组一旦定义了,数组的长度是不可以变更的;

int arr[15] = {0};//int 默认为0,float double 默认为0.0
char arr_char[4+1] = {'t','e','s','t'};//4是数组内容长度,1是存储结束符使用'\0'

【备注说明】

长度省略:数据值的个数就是数组的长度

长度未省略:数据的个数<=长度

内存:软件在运行过程中,用来临时存储粗数据;

动作:读/写

内存地址:在内存中申请空间的编号

作用:快速管理和操作内存中的数据

内存的读和写都需要依赖于内存的地址:address,size,offset(偏移量)

内存地址的规则:32位操作系统:32字节的,最大可以支持内存:4GB

数组的元素访问:

1.使用for 取数组的下标(索引)读取数组中的内容,或进行修改;

2.使用指针读取数组中的内容,或进行修改

int arr[10] = {1,2,3,4,5,6,7,8,9,10};//定义一个int类型的数组,长度10;
int len = sizeof(arr)/sizeof(arr[0]);//获取一个数组的长度

int* arr1 = arr;//定义指针获取数组arr的首地址
int* arr2 = &arr[0];  
printf("arr len is %d\n",len);
printf("arr first address is %p\n",arr1);
printf("arr first address is %p\n",arr2);

//使用指针访问数组
for(int j=0;j<len;j++)
{
	printf(" %d",*arr1++);
}
printf("\narr data is:");
for(int i=0;i<len;i++)
{
	printf(" %d",*arr2++);
}
//使用下标访问数组内容
for(int i;i<len;i++)
{
    printf(" %d",arr1);
}

变量地址:说的是变量的首地址, &a 取变量a的地址(4字节) 以上基于32位操作系统

arr[0] :0说的内存的偏移量,偏移量大小和数据类型相关;数组长度=总长度/数据类型占用的字节数;

数组作为函数的参数

传递的是数组的首地址;常见使用*指针代替,很少传递数组;

传递数组的长度,先声明,传入形参;

其他说明

数组越界(指针越界)

最小索引:0

最大索引:数组的长度 - 1  这样可以保证数组索引不会越界;

特殊情况

sizeof运算的时候,不会退化,arr还是一个整体;

&arr 获取地址的时候,会退化,arr还是一个整体;

int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    int len = sizeof(arr)/sizeof(arr[0]);
    //获取数组的首地址的两种方式
    int* arr1 = arr;
    int* arr2 = &arr[0];  
    printf("arr size is %d\n",sizeof(arr));
    printf("arr first address is %p\n",arr);
    printf("arr offset len is %p\n",&arr+1);//&arr的步长为数据类型*数组长度

}
二维数组

        在C语言中,二维数组是一种数据结构,它包含多个一维数组。二维数组可以被看作是矩阵,其中每个元素都是一个固定大小的数组。二维数组在C语言中非常有用,尤其是在处理表格数据或矩阵运算时。

void twoDimensionalArray()
{
    int arr[3][5]=//这样定义的是相同长度的二维数组
    {
        {1,2,3,4,5},
        {11,22,33,44,55},
        {111,222,333,444,55}
    };
    int (*p)[5] = arr;//数组指针,利用指针遍历二维数组
    for(int i=0;i<3;i++)
    {
        for(int j=0;j<5;j++)
        {
            printf("%d ",*(*p+j));
        }
        printf("\n");
        p++;
    }
}

指针

        指针也就是内存地址,指针变量是用来存放内存地址的变量,在同一CPU构架下,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。

作用:查询(读取)和存储(写入)、参数传递、内存管理等

指针变量--存储的是内存地址;

数据类型 * 变量名;

指针变量占用的大小,和数据类型无关,和编译器相关的(32位:32字节,64位:64字节);

给指针变量赋值的时候,不能吧一个数值赋值给到指针变量;(指针对应的是内存的地址);

int a = 10;
int* p = &a;//p-指针变量名称,获取整型变量a,在内存中的地址;

printf("the a address is %p\n",p);//打印变量a在内存中的四肢
printf("the a value is %p\n",*p);//打印变量a的取值(通过指针)其中的*为解引用

指针(函数)中的作用
  1. 1.操作其他函数中的变量
  2. 2.函数返回值多个
  3. 3.函数的结果和计算状态分开
  4. 4.方便操作数据和函数
  5. 作用一:操作其他函数中的变量
  6. void swap(int *num1,int *num2)
    {
        int temp = *num1;
        *num1 = *num2;
        *num2 = temp;
    }
    
    int main()
    {
        int a=10;
        int b=20;
        swap(&a,&b);//交换的是变量对应的地址
        printf("调换后的数据为 a=%d,b=%d",a,b);
    }
    
    

    补充说明

    函数变量的生命周期和函数相关,函数结束了,变量也会消失;

    此时在其他函数中,就无法通过指针使用了,

    如果不想函数中的变量被收回,可以在变量的前面增加static 关键字进行修饰;

  7. int* method(void)
    {
        static int a = 10;
        return &a ;
    }
    int main()
    {
        int *p = method();
        printf("the a in method value is %d\n",*p);
    }
    
    
    作用二:在函数中返回多个数值,方便开发者理解
  8. void getArrMaxandMin(int*arr,int len,int *max,int* min)
    {
        *max = arr[0];
        *min = arr[0];
        for(int i = 1;i < len;i++)
        {
            //取最大值
            if(arr[i] > *max)
            {
                *max = arr[i];
            }
            //取最小值
            if(arr[i] < *min)
            {
                *min = arr[i];
            }
        }
    }
    
    int main()
    {
        int arr[10] = {1,2,3,4,5,6,7,8,9,10};
        int len = sizeof(arr)/sizeof(arr[0]);
        int max = 0;
        int min = 0;
        getArrMaxandMin(arr,len,&max,&min);
    }
    作用三:利用指针将函数的结果和状态分开
  9. int getRemainder(int a,int b,int *remainder)
    {
        if (b == 0)
        {
            return 1;
        }
        *remainder = a%b;
        return 0;
    }
    
    int main()
    {
        int a=10;
        int b=20;
        int res=0;
        int flag = getRemainder(a,b,&res);
        if (!flag)
        {
            printf("the res value is %d\n",res);
        }
        else 
        {
            printf("the flag value is%d\n",flag);
        }
    }
    作用四:方便操作数据和函数
  10. 指针高级阶段(指针的计算,二级指针和多级指针、数组和指针、函数和指针)

指针的运算

运算符:+、-

步长(偏移量):指针移动一次的字节数;偏移量大小与数据类型相关;

char(1字节) int(4字节)short(2字节) long(4字节) long long (8字节)

int a = 10;
int* p1 = &a;
printf("the a address id %p\n",p1);
printf("the p1+1 address id %p,the p1+1 value is %d \n",p1+1,*(p1+1));
printf("the P1+2 address id %p,the p1+1 value is %d\n",p1+2,*(p1+2));

有意义的操作:

指针跟正整数进行+、-操作(每次移动N个步长,偏移量);

指针和指针之间进行减操作(间隔步长,内存中空间偏移量有多大);

无意义操作

指针跟正整数进行乘除操作(指针指向不明确,引起野指针,指针越界)

指针和指针进行加、乘、除;

【备注说明】

野指针:指针指向的空间未分配;

悬空指针:指针指向的空间已经分配,但是已经被释放了;

Linux系统中遇到段错误,常见的原因都是由于指针使用不当引起的;

void 类型指针

void *p; 不可以进行指针的运算(+、-);

无法获取数据,无法计算,但是可以接受任何地址(优点);

不同类型的指针之间,是不能互相赋值的,void类型的指针打破了上面的观念,void没有任何类型;

优势:可以接受任意类型的指针记录的内存地址;

缺点:void类型的指针,无法获取变量中的数据,也不能进行指针的加减计算;

int main()
{
    int abs = 10;
    int abs1 = 20;
    int* pabs = &abs;
    int* pabs1 = &abs1;
    printf("the abs address is %p\n",pabs);
    printf("the abs1 address is %p\n",pabs1);
    void* p3 =pabs;
    void* p4 = pabs1;
    printf("the p3 address is %p\n",p3);
    printf("the p4 address is %p\n",p4);
}

使用void类型优化swap函数,使得swap_ex函数的通用型增加

void swap_ex(void* pnum,void* pnum2,int len)
{
    char* p1 = pnum;
    char* p2 = pnum2;
    char temp = 0;
    for(int i = 0;i < len;i++)
    {
        temp = *p1;
        *p1 = *p2;
        *p2 = temp;
        p1++;
        p2++;
    }
}

int main()
{
    int a=100;
    int b=200;
    swap_ex(&a,&b,sizeof(a));//不在受数据类型的限制,交换数据必须相同的数据类型
    printf("调换后的数据为 a=%d,b=%d\n",a,b);
    
    char c = 128;
    char d = 255;
    swap_ex(&c,&d,sizeof(c));//不在受数据类型的限制,交换数据必须相同的数据类型
    printf("调换后的数据为 c=%d,d=%d\n",c,d);
}

二级指针

数据类型 *指针名

指针的数据类型:跟指向空间中的数据类型保持一致的;

示例:int ** p;

第一个*:数据类型,和int 数据变量是一个整体,表示内存存储数据的类型;

第二个*:定义指针的特殊标志;

作用:二级指针可以操作一级指针记录的地址

int main()
{
    int a = 10;
    int b = 20;
    int* p5 = &a;
    int** p6 = &p5;
    //利用二级指针修改一级指针内存的地址
    *p6 = &b;
    //利用二级指针获取变量中记录的数据
    printf("the a address is %p\n",&a);
    printf("the b address is %p\n",&b);
    printf("the p5 address is %p\n",p5);
    printf("the p6 address is %d\n",**p6);//*解引用,一个*解一级指针引用

}
数组指针

概念:指向数组的指针,叫做数组指针(数组的指针);

作用:方便的操作数据中的各种数据

int* p = arr;

int (*p)[3] = arr;

int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    int len = sizeof(arr)/sizeof(arr[0]);
    //获取数组的首地址的两种方式
    int* arr1 = arr;
    int* arr2 = &arr[0];  
    printf("arr first address is %p\n",arr1);
    printf("arr first address is %p\n",arr2);
    printf("arr len is %d,and arr data is:",len);
    for(int j=0;j<len;j++)
    {
        printf(" %d",*arr1++);
    }
    printf("\narr data is:");
    for(int i=0;i<len;i++)
    {
        printf(" %d",*arr2++);
    }
}
指针数组

存放指针的数组

void twoDimensionalArray_Point()
{
	//定义三个一维数组
	int arr[7]={1,2,3,5,6};
	int arr1[7]={0,9,8,7,6,5,4};
	int arr2[7]={0};
	//定义一个数组,把三个一维数组放到二维数组中
	int *arr_twoDimensionalA[3]={arr,arr1,arr2};
	//获取指针(二级指针)
	int **p_arr = arr_twoDimensionalA;
	for(int i=0;i<3;i++)
	{
		for(int j=0;j<7;j++)
		{
			printf("%d",*(*p_arr+j));
		}
		printf("\n");
		//移动二维数组的指针,继续遍历下一个一维数组
		p_arr++;
	}

    //把五个字符串的指针放到一个数组中,指针数组
	char* p_arr[5] = {"hello","world","nihao","zhongguo","shijie"};
	for(int i = 0;i < 5;i++)
	{
		printf("the string is %s\n",p_arr[i]);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值