level 5
西安恩仪联教育
楼主
本文有西安恩仪联教育科技有限公司整理和发布,欢迎转载和分享
目录:
1、void类型指针。
2、含有void*类型指针函数实现。
void类型的指针在c中是一个重要的概念,是想深入学习c语言必须要了解的技术点。很多学习c语言的人都对这个类型指针一知半解,导致工程中出现很多不该出现的错误。例如很多人分不清strcpy()函数和memcpy()函数的区别;大家非常熟悉的函数memset()的接口多数人都写不对。诸如此类的问题都是对void*这个指针不理解导致的,本文主要分析void类型指针的概念、使用方法和注意的问题。帮助大家认识这类指针,在实际开发工作中能够很好的使用它。
一、void类型指针。
大家在学习和使用c语言开发项目的过程中,在哪些地方见过void *类型的指针,我们能否列举出多个例子来证明void *类型的普遍性和重要性。在这里给各位列出几个使用void *类型指针的使用场景:
1、内存管理函数中,各位非常熟悉函数memset(),接口如下:
void *memset(void *s, int c, size_t n);
该函数可以初始化任意类型的空间,但是只能按照字节初始化。一个函数的参数能够接收各种类型的指针,这个参数的类型就是void *类型的指针变量。同理可以列举出下面函数,都是含有void *类型的参数:
void *memcpy(void *dest, const void *src, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
void *memmove(void *dest, const void *src, size_t n);
这些函数的共同特点是按照字节处理数据,不区分数据类型。很多人除了memset()函数以外没有使用过其它函数,所以导致理解不到位。开发c/s模式程序时,客户端和服务器之间需要传输数据包,这种数据包的组包需要使用memcpy()函数和指针移动,这样就能通过固定的几个类型组合出用户需要的各种数据包,数据包是一个二进制流包,并不是某一个固定的数据类型,这一点如果不理解,可以查阅相关资料,在此不在过多赘述。
2、文件读写函数中:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
大家思考一下文件读写函数中为什么含有void *类型的参数。文件仅是保存数据的功能,文件本身按照字节保存数据,对数据并不解析。在文件看来一切都是字节流,不管是文本文件、歌曲文件、电影文件、还是软件生产的数据文件都是一堆字节。那么读写文件的函数在设计时该如何考虑自己的参数,同样的读写函数要读写各种不同类型的文件,参数的类型就是void *类型的指针。读写函数只是搬运工,读函数将硬盘文件中的数据搬到指定内存中,写函数将指定内存中数据搬到硬盘指定的文件中,什么类型的数据都可以搬运,所以参数就设计为void *类型的指针。
3、网络数据收发函数:
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
网络收发函数也是搬运工,将数据由a地方搬运到b地方,什么类型的数据都可以搬运,具有通用性,不可能为每种数据类型都开发相应网络收发函数。引入void *类型的指针就解决问题了,不管什么类型的数据,都是由若干个字节组成的,只要按照字节搬运就能够传输各种类型的数据。
以上列出三个应用场景,含有void *类型参数的函数公共特点总结如下:
(1)处理数据不区分类型,按照字节处理。
(2)和void *类型参数配合有一个以字节为单位表示大小的参数。
(3)函数的功能具有公共性,主要体现处理不同类型的数据。
用户在开发项目时,自己设计的函数,处理数据类型往往比较具体,所以很少出现用户自定义的函数中参数有void*修饰的情况。但是并不代表没有,后面随着大家能力不断提升就会遇到。
二、含有void*类型指针函数实现。
很多企业在考察面试者对void *这类指针的理解时,都会出这样的题目:请编写memset()这个函数的源代码。首先函数的接口要写对,然后按照字节处理。
void *memset(void *s, int c, size_t n)
{
char *st = (char *)s;
for(int i = 0;i < n;i++)
{
*(st + i) = c;
}
return s;
}
实现步骤分为两步:
第一步:将void *转换为char *。注意转为char *并不是要处理字符串,而是按照字节处理数据。char类型的数据正好占一个字节,所以转为char *类型。
第二步:按照字节一个一个处理。该题目按照字节一个一个的赋值,共计赋n个字节,用一个for循环就可以搞定。
同样的编写memcpy() memcmp() memmove()的函数源代码方式和上面这个题目的思维是一致的。注意 memcpy()和memmove()函数功能几乎是一致的,唯一的区别是memmove()相比memcpy()更安全,更可靠,如果项目赋值的区域有重叠情况,则应该使用memmove()函数,否则出错。如果区域不重叠,两个函数的功能是一样的。
2025年08月21日 09点08分
1
目录:
1、void类型指针。
2、含有void*类型指针函数实现。
void类型的指针在c中是一个重要的概念,是想深入学习c语言必须要了解的技术点。很多学习c语言的人都对这个类型指针一知半解,导致工程中出现很多不该出现的错误。例如很多人分不清strcpy()函数和memcpy()函数的区别;大家非常熟悉的函数memset()的接口多数人都写不对。诸如此类的问题都是对void*这个指针不理解导致的,本文主要分析void类型指针的概念、使用方法和注意的问题。帮助大家认识这类指针,在实际开发工作中能够很好的使用它。
一、void类型指针。
大家在学习和使用c语言开发项目的过程中,在哪些地方见过void *类型的指针,我们能否列举出多个例子来证明void *类型的普遍性和重要性。在这里给各位列出几个使用void *类型指针的使用场景:
1、内存管理函数中,各位非常熟悉函数memset(),接口如下:
void *memset(void *s, int c, size_t n);
该函数可以初始化任意类型的空间,但是只能按照字节初始化。一个函数的参数能够接收各种类型的指针,这个参数的类型就是void *类型的指针变量。同理可以列举出下面函数,都是含有void *类型的参数:
void *memcpy(void *dest, const void *src, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
void *memmove(void *dest, const void *src, size_t n);
这些函数的共同特点是按照字节处理数据,不区分数据类型。很多人除了memset()函数以外没有使用过其它函数,所以导致理解不到位。开发c/s模式程序时,客户端和服务器之间需要传输数据包,这种数据包的组包需要使用memcpy()函数和指针移动,这样就能通过固定的几个类型组合出用户需要的各种数据包,数据包是一个二进制流包,并不是某一个固定的数据类型,这一点如果不理解,可以查阅相关资料,在此不在过多赘述。
2、文件读写函数中:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
大家思考一下文件读写函数中为什么含有void *类型的参数。文件仅是保存数据的功能,文件本身按照字节保存数据,对数据并不解析。在文件看来一切都是字节流,不管是文本文件、歌曲文件、电影文件、还是软件生产的数据文件都是一堆字节。那么读写文件的函数在设计时该如何考虑自己的参数,同样的读写函数要读写各种不同类型的文件,参数的类型就是void *类型的指针。读写函数只是搬运工,读函数将硬盘文件中的数据搬到指定内存中,写函数将指定内存中数据搬到硬盘指定的文件中,什么类型的数据都可以搬运,所以参数就设计为void *类型的指针。
3、网络数据收发函数:
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
网络收发函数也是搬运工,将数据由a地方搬运到b地方,什么类型的数据都可以搬运,具有通用性,不可能为每种数据类型都开发相应网络收发函数。引入void *类型的指针就解决问题了,不管什么类型的数据,都是由若干个字节组成的,只要按照字节搬运就能够传输各种类型的数据。
以上列出三个应用场景,含有void *类型参数的函数公共特点总结如下:
(1)处理数据不区分类型,按照字节处理。
(2)和void *类型参数配合有一个以字节为单位表示大小的参数。
(3)函数的功能具有公共性,主要体现处理不同类型的数据。
用户在开发项目时,自己设计的函数,处理数据类型往往比较具体,所以很少出现用户自定义的函数中参数有void*修饰的情况。但是并不代表没有,后面随着大家能力不断提升就会遇到。
二、含有void*类型指针函数实现。
很多企业在考察面试者对void *这类指针的理解时,都会出这样的题目:请编写memset()这个函数的源代码。首先函数的接口要写对,然后按照字节处理。
void *memset(void *s, int c, size_t n)
{
char *st = (char *)s;
for(int i = 0;i < n;i++)
{
*(st + i) = c;
}
return s;
}
实现步骤分为两步:
第一步:将void *转换为char *。注意转为char *并不是要处理字符串,而是按照字节处理数据。char类型的数据正好占一个字节,所以转为char *类型。
第二步:按照字节一个一个处理。该题目按照字节一个一个的赋值,共计赋n个字节,用一个for循环就可以搞定。
同样的编写memcpy() memcmp() memmove()的函数源代码方式和上面这个题目的思维是一致的。注意 memcpy()和memmove()函数功能几乎是一致的,唯一的区别是memmove()相比memcpy()更安全,更可靠,如果项目赋值的区域有重叠情况,则应该使用memmove()函数,否则出错。如果区域不重叠,两个函数的功能是一样的。