首页 > 其他分享 >嵌入式初学-C语言-二四

嵌入式初学-C语言-二四

时间:2024-08-15 18:54:41浏览次数:9  
标签:p2 include int void 嵌入式 内存 C语言 二四 指针

Void与void*的区别

定义:

Void:空类型,是数据类型的一种

Void*:是指针类型,是指针类型的一种,可以匹配任何类型的指针,类似于通配符

Void

说明:void作为返回值类型使用,表示没有返回值,作为参数,表示形参列表为空,在调用函数时不能给实参

// 函数声明
void fun(void); // 等效于 void fun();
// 函数调用
fun();

Void*

说明:

  1. void*是一个指针类型,但是该指针的数据类型是不明确的,无法通过解引用获取内存中的数据,因为void*不知道访问几个内存单元
  2. void*是一种数据类型,可以作为函数返回值类型,也可以作为形参类型
  3. void*类型的变量在使用之前必须强制类型转换
int *p = (int*)malloc(4);
double *p2 = (double*)malloc(8);

举例:

#include <stdio.h>
#include <stdlib.h>
// 函数定义
void* fun(void* p) // 指针函数(返回值类型是指针的函数,此时返回的是不明确类型,需要外部强转)
{
int *p;
// double *p;
// long *p;
// char *p;
return p;
}
// 函数调用
void main()
{
int *p;
void* a = fun(p);// 这种接收方式,实际上没有意义
printf("%p\n",a);// 可以正常打印,打印出一个地址
*a = 10;// 编译报错,void*变量不能解引用访问数据
int *w = (int*)a;
*w = 10;// 编译和运行正常,void*变量a在使用前已经强制类型转换了,数据类型明确了,访问的内存
单元明确了。
}

说明:

  1. void*作为返回值类型:这个函数可以返回任何类型(char*  int*  double*)的指针
  2. void*作为形参的类型:这个函数在调用时,可以给任意类型的指针

总结:

  1. void*类似于通配符,不能对void*类型的变量解引用(因为不明确内存单元的大小)
  2. void*在间接访问(解引用)前要强制类型转换,但不能太随意,否则存和取的数据类型不一致

内存操作

我们对于内存的操作借助于string.h这个库提供的内存操作函数。

内存填充

头文件:#include<string.h>

函数原型:void*memset(void*s,int c,size_t n);

函数功能:填充s开始的堆内存前n个字节,使得每个字节值为c

函数参数:

  1. void*s:待操作内存的首地址
  2. int c:填充的字节数据
  3. size_t n:被填充的字节数

返回值:返回s

注意:c常常设置为0,用于动态内存初始化

/**
* 内存操作函数-memset
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test1()
{
// 在堆内存申请了一块存储空间
int *p = (int*)malloc(4 * sizeof(int));
if(!p)
{
puts("内存分配失败!");
return;// 后续代码不需要执行
}
// 给这块内存进行初始化操作(填充)
memset(p,0, 4 * sizeof(int));
printf("%d\n",*(p+1));
// 内存使用完毕,进行回收
free(p);
p = NULL;
}
int main()
{
test1();
return 0;
}

内存拷贝

头文件:#include<string.h>

函数原型:

  1. void*memcpy(void*dest,const void*src,size_t n);适合目标地址与源地址内存无重叠的情况
  2. void*memmove(void*dest,const void*src,size_t n);

函数功能:拷贝src开始的堆内存空间前n个字节到dest对应的内存中

函数参数:

  1. void*dest:目标内存的首地址
  2. void* src:源内存首地址
  3. size_t n:被拷贝的字节数

返回值:返回dest

注意:内存申请了几个内存空间就访问几个内存空间,否则数据不安全

注意:memcpy与memmove一般情况下是一样的,更建议使用memmove进行内存拷贝因为mememove函数是从自适应(从后往前,从前往后)拷贝,当我们被拷贝的内存和目的地的内存有重叠时数据不会出现拷贝错误,而memecpy函数是从前往后拷贝,当被拷贝的内存和目的地有重叠时数据会出现拷贝错误

/**
* 内存操作函数-memcpy|memmove
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test1()
{
// 申请内存
// int *p1 = (int*)malloc(4 * sizeof(int));
// int *p2 = (int*)malloc(6 * sizeof(int));
// 给p1,p2填充数据,可以使用for循环..
// for(int i = 0; i < 4; i++)
// p1[i] = 10 + i;
// memset(p2,0,6 * sizeof(int));
// 创建数组
int p1[4] = {11,12,13,14};
int p2[6] = {21,22,23,24,25,26};
// 将p1中的数据通过内存拷贝函数,拷贝到p2
// memcpy(p2+2,p1+1,2*sizeof(int)) // int p2[6] = {21,22,12,13,25,26}
memmove(p2+2,p1+1,2*sizeof(int));
// 测试输出数组
for(int i = 0; i < 4; i++)
printf("%4d",p1[i]);
printf("\n");
for(int j = 0; j < 6; j++)
printf("%4d",p2[j]);
printf("\n");
// 如果使用手动分配的指针,一定要记得释放内存
// free(p1);
// free(p2);
// p1 = NULL;
// p2 = NULL;
}
int main()
{
test1();
return 0;
}

内存比较

头文件:#include<string.h>

函数原型:int memcmp(void*dest,const void*src,size_t n)

函数功能:比较src和dest所代表的内存前n个字节数据

函数参数:

  1. void*dest:目标内存首地址
  2. const void*src:源内存首地址
  3. size_t n:比较的字节数

返回值:

  1. 0:数据相同
  2. >0:dest中的数据大于src(目标大于源)
  3. <0:dest中的数据小于src

注意:n一般和src,dest的总容量一样,如果不一样内存比较的结果就不确定

案例:

/**
* 内存操作-memcmp
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test1()
{
// 申请内存
int *p1 = (int*)malloc(3*sizeof(int));
int *p2 = (int*)malloc(4*sizeof(int));
// int p1[4] = {1,0,3,6};
// int p2[4] = {1,2,3,4};
// int result = memcmp(p1,p2,4*sizeof(int));
*p1 = 65;
*p2 = 70;
char *a = (char*)p1;// 类型转换
char *b = (char*)p2;
printf("%c,%c\n",*a,*b);
int result = memcmp(a+1,b+1,1*sizeof(char));
printf("%d\n",result);
}
int main()
{
test1();
}

内存查找

头文件:#include<string.h>

函数原型:void *memrchr | *memchr(const void *s, int c, size_t n);

函数功能:在s开始的堆内存空间前n个字节中查找字节数据c

函数参数:

  1. const void *s:待操作内存首地址;
  2. int c:待查找的字节数据
  3. size_t n:查找的字节数

返回值:返回查找到的字节数据地址

注意:如果内存中没有重复数据,memchr和memrchr结果是一样的,若果有重复数据memchr和memrchr结果就不一样

案例:

/**
* 内存操作-memchr | memrchr
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 声明外部函数
extern void *memrchr(const void *s,int c,size_t n);
void test1()
{
// 申请内存
int *p = (int*)malloc(4*sizeof(int));
if(!p)
{
puts("内存分配失败!");
return;
}
// 给变量赋值
for(int i = 0; i < 4; i++)
{
p[i] = i * 2;
}
p[3] = 4;
// 输出
for(int i = 0; i < 4; i++)
{
printf("%d,",p[i]);
}
printf("\n");
// 内存查找 memchr
int *x = (int*)memchr(p,4,4*sizeof(int));
printf("%p--%p--%d\n",x,p,*x);
// 内存查找 memrchr
int *y = (int*)memrchr(p,4,4*sizeof(int));
printf("%p--%p--%d\n",y,p,*y);
// 回收内存
free(p);
p = NULL;
}
int main()
{
test1();
}

本章小结

1.  指针就是地址。变量的指针就是变量的地址。指针变量就是地址变量。

     指针是地址本身,指针变量是用来存放地址的变量。

2.  指向   把谁的地址存放在指针变量中,该指针变量就指向谁

3.  深入掌握对数组操作中怎样正确使用指针。

4.  有关指针变量的定义形式归纳比较,见表8-4。

5.  指针运算小结

  ① 指针变量加(减)一个整数

       p++、p--、p+i、p-i、p+=i、p-+i 等均使指针变量p加(减)一个整数。改变了指向的地址值。

  ②  指针变量赋值 

         不要把一个整型数赋给指针变量

   ③  指针变量可以赋空值

          p=NULL    即不指向任何变量

   ④  两个指针变量可以相减

         两个指向同一数组的指针变量可以相减,得到两个指针之间元素的个数,但相加无意义

   ⑤  两个指针变量比较

         两个指向同一数组的指针变量可以比较,指向前面元素的指针“小于”指向后面元素的指针变量

标签:p2,include,int,void,嵌入式,内存,C语言,二四,指针
From: https://blog.csdn.net/MaBaB/article/details/141229425

相关文章

  • C语言学习笔记 Day13(复合类型/自定义类型)
    Day13 内容梳理:目录Chapter9 复合类型(自定义类型)9.1结构体(1)结构体变量定义、初始化(2)嵌套结构体(3)结构体赋值(4)结构体和指针(5)结构体做函数参数9.2共用体(联合体)9.3枚举9.4typedef关键字Chapter9 复合类型(自定义类型)9.1结构体有时需要将不同类型的数组......
  • C语言无脑小游戏三子棋程序
    #include<stdio.h>#include<time.h>#include<stdlib.h>#include<windows.h>#defineROW3#defineCOL3voidmenu();//菜单函数声明voidgame();//游戏函数声明voidInit_board(charboard[ROW][COL],introw,intcol);//棋盘初始化函数声明voidDisplay_board......
  • C语言最后一讲——预处理超详解
    文章目录1.预定义符号2.`#define`定义常量3.`#define`定义宏4.带有副作用的宏参数5.宏替换的规则6.宏函数的对比7.#和##7.1#运算符7.2##运算符8.命名约定9.`#undef`10.命令行定义11.条件编译12.头文件的包含12.1头文件被包含的方式:12.1.1本地文......
  • C语言中的操作符:深入解析与应用
    引言C语言提供了丰富的操作符,用于执行算术运算、逻辑判断、位操作等。这些操作符是编程语言中的基础构件,它们使得程序能够进行复杂的数据处理和逻辑控制。本文将详细介绍C语言中的各种操作符,包括它们的类型、用法和一些实际应用示例。操作符的分类算术操作符算术操作符用于......
  • C语言内存管理,分配、使用、释放以及安全性
    在C++中,内存分配是通过几种不同的方式来管理的。这包括自动存储、静态存储和动态存储。下面分别解释这些存储类别以及如何使用它们进行内存分配。#1,自动存储(AutomaticStorage)这是最常用的存储类型,当一个变量在函数内被声明时,它会自动获得存储空间,并且在函数结束时自动释放。例......
  • C语言指针详解-上
    C语言指针详解-上前言1.指针的基本概念1.1指针是什么1.2指针的声明与初始化1.3取地址符`&`和解引用符`*``&`运算符用于**获取变量的地址**`*`运算符用于访问指针指向的值2.指针的类型常见数据类型的指针指针与数组、字符串数组指针结构体指针函数指针二级指针void指......
  • 嵌入式linux mkdir: cannot create directory 'test': Read-only file system
    这个错误表明你尝试在嵌入式Linux系统上创建一个名为'test'的目录时失败了,因为文件系统被挂载为只读模式。在只读模式下,你无法修改文件系统的内容,包括创建、删除文件或目录。解决方法:1.重新挂载文件系统为读写模式。你可以使用mount命令重新挂载文件系统,并指定读写权限。例如:......
  • 译 如何实现一个哈希表(C语言)
    原文:https://benhoyt.com/writings/hash-table-in-c/概要:一个关于如何用C语言实现一个简单的哈希表数据结构的说明。我会简要演示线性与二分搜索,然后设计实现一个哈希表。我的目标是证明哈希表内部并不可怕,相反——在一定的约束内——是足够简单到可以从头实现的。标签:线性搜索......
  • C语言结构体内存对齐
    结构体或许小伙伴们都知道,或许也能够做到熟悉的去运用结构体,但你们有没有想过:整型数组存放的数据都是整型,字符数组存放的数据都是字符,它们类型相同,所以也都能够做到在内存中紧密的存储,而结构体中存放的数据各种各样,它们的存储是否能做到在内存中紧密排列呢?又或者说,结构体的内存......
  • 【C语言】sizeof 和 strlen
    sizeof和strlen的对比sizeof在学习操作符的时候,我们学习了sizeof,sizeof计算变量所占内存内存空间大小的,单位是字节。如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小。sizeof只关注占用内存空间的大小,不在乎内存中存放什么数据。比如:#include......