对于指针 void*以及void **等的一些理解与疑惑

本人最近学习过程中老是遇到一些指针操作,由于基础薄弱,查阅了很多资料仍然对于多重指针存在一伙,现在把我对于指针的理解以及疑惑写出来,恳请网友帮我指点迷津。

首先,void* 定义一个void类型的指针,它不指向任何类型的数据,意思是,void指针“指向空类型”或“不指向确定的类型”,而不要理解为void指针能指向“任何的类型”数据。简而言之:void只提供一个地址,没有指向。可以把非void指针赋给void指针,但不能把void指针直接赋给非void指针,必须先强转。例如:

void *pv;
char *pc;
char c = 'c';

pc = &c;
pv = pc;        //合法
pc = pv;        //非法,void*指针不能直接赋值给非void指针
pc = (char*)pv; //合法,把void*指针强转成char*型后在赋值

对于多重指针, **相当于指向指针的指针,本质还是一个指针,只是它指向的是一个地址。&很简单,即同级运算,从右到左,先进行地址&运算再进行指针运算。 例如:

int i1 = 1;
void *pv1 = &i1;
void **ppv1 = &pv1;
int **ppout;

这里可以得到ppv1是一个地址值,*ppv1也是一个地址值,**ppv1才是i1真正的值。

OK----------------------------------------------------------------------

以上是对void*、void**简单的理解,下面来看一个简单的实例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h>

struct thrd{
    
    
	int var;
	char str[256];
};

void sys_err(const char *str)
{
    
    
    perror(str);
    exit(1);
}
  
void *tfn(void *arg)
{
    
    
	struct thrd *tval;

	tval = malloc(sizeof(tval));
	tval->var = 100;
	strcpy(tval->str, "hello thread");

	return (void *)tval;
}

int main(int argc, char *argv[])
{
    
    
    pthread_t tid;
	struct thrd *retval;

	int ret = pthread_create(&tid, NULL, tfn, NULL);
	if(ret != 0)
		sys_err("pthread_create error");

	ret = pthread_join(tid, (void **)&retval);
	if(ret != 0)
		sys_err("pthread_join error");

	printf("child thread exit with var = %d,str = %s\n", retval->var, retval->str);

    pthread_exit(NULL);
}

这里存在我在Linux shell终端下编写多线程程序的时候遇到的很多不懂的地方,主要是对于int pthread_join(pthread_t thread, void **retval);这个函数的不理解,方便大家看程序,本程序的功能很简单,利用int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);函数创建一个子线程,子线程里面实现对结构体的赋值,由pthread_join阻塞回收线程,最后把在子线程函数里赋值的结构体在主线程中打印出来,这里我存在最大的疑惑就是pthread_join的第2个参数,这里使用void **类型的参数来得到子线程的返回值,我其中一个不明白的地方就是这里为什么要用二重指针来传递参数,除去此地方,经过我想很久,理解到线程所调用的函数void *tfn(void *arg)返回值为void *类型的指针,返回值tval通过return (void *)tval强行改变类型为void *之后赋值给&retval,使得retval的地址指向tval(个人理解:这里(void **)就是把&retval声明为二重指针,此时加括号就与定义二重指针不加括号一样,只是声明变量类型,*符号并没有读取变量的作用) ,之后就可以通过retval访问tval的值,解释起来很牵强,文章发出来就是想要咨询一下各位大佬的意见,指针这里实在学不太懂,如果有懂得大佬,还请明示!

猜你喜欢

转载自blog.csdn.net/qq_42955211/article/details/113100335