user-0 提问: （void *）xxx 和*（void **）（&xxx）求解区别 

回复:
user: user-1
content: 仅供参考：#include <stdio.h> #include <stdlib.h> #include <malloc.h> int **newarr2d(int rows,int cols) {     int **p,i;      p=(int **)malloc(rows*sizeof(int *));     if (NULL==p) exit(1);     for (i=0;i<rows;i++) {         p[i]=(int *)malloc(cols*sizeof(int));         if (NULL==p[i]) exit(1);     }     return p; } void deletearr2d(int **p,int rows) {     int i;      for (i=0;i<rows;i++) {         free(p[i]);     }     free(p); } int main() {     int **arr2d,i,j,r,c;      r=4;     c=5;     //在堆中开辟一个4×5的二维int数组     arr2d=newarr2d(r,c);     for (i=0;i<r;i++) {         for (j=0;j<c;j++) {             arr2d[i][j]=i*c+j;         }     }     for (i=0;i<r;i++) {         for (j=0;j<c;j++) {             printf(" %2d",arr2d[i][j]);         }         printf("\n");     }     deletearr2d(arr2d,r);      r=6;     c=3;     //在堆中开辟一个6×3的二维int数组     arr2d=newarr2d(r,c);     for (i=0;i<r;i++) {         for (j=0;j<c;j++) {             arr2d[i][j]=i*c+j;         }     }     for (i=0;i<r;i++) {         for (j=0;j<c;j++) {             printf(" %2d",arr2d[i][j]);         }         printf("\n");     }     deletearr2d(arr2d,r);      return 0; } //  0  1  2  3  4 //  5  6  7  8  9 // 10 11 12 13 14 // 15 16 17 18 19 //  0  1  2 //  3  4  5 //  6  7  8 //  9 10 11 // 12 13 14 // 15 16 17 //

user: user-1
content: 《牛肉干》 C语言上机课，某女同学偷偷吃起牛肉干。 有一粒牛肉干掉到了键盘上，卡在7和8键之间。 女同学就在键盘上抠啊、抠啊、抠啊…… 程序里一行代码变成这个样子： int *pa=&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&a; 后来的结局是 ————程序顺利通过编译，运行结果正确！

user: user-2
content: 由于void就是不检查数据类型,所以,对于编译器来说, void* 和 void** ,甚至后面n个 * ,都是一样的.  问题的关键在于,让我们这些编程的人可以区分.  原则上,void* 可以是一个一级指针,二级指针,甚至是n级指针. 但我们的使用习惯是, 一个 * 代表一级指针,多级指针就用n个*表示.    在实际使用的时候, 如果告诉你, void* 是一个n级指针,你不会觉得别扭吗?假如是一个多级指针,由于用void*表示,也由于别人使用的时候一个不小心当成1级指针来处理(这种错误非常容易出现,绝对不是小心一点就能避免的),bug就出现了.而且由于是void*类型,编译器不做检查,错误查找也非常麻烦.  所以,习惯上,实际使用的时候,多级指针还是用多个*表示的居多,这样看着也明白了,用起来也就不那么容易出错了.

user: user-0
content: 引用 11 楼 fefe82 的回复:[quote=引用 10 楼 qq_34717051 的回复:] [quote=引用 9 楼 fefe82 的回复:] [quote=引用 8 楼 qq_34717051 的回复:] [quote=引用 7 楼 fefe82 的回复:] 给程序。。。  下面是程序代码   下面 还有个动态模块  #include <stdio.h> #include <dlfcn.h>    int (*func)(int , int );  int main(int argc, char **argv) { 	int a = 5,b = 7; 	void *handle; 	if (!(handle = dlopen("./mymath.so", RTLD_NOW))) 			{ 				printf("11111111\n"); 			}  	 	(void *)(func) = dlsym(handle, "add");   //报错   	printf("%d\n", func(a,b));   	*(void **)(&func) = dlsym(handle, "sub");  	printf("%d\n", func(a,b)); 		  }   int add(int a,int b) { return (a+b); } int sub(int a,int b) { return (a-b); } [/quote]  (void *)(func) 强制类型转换结果是一个临时变量（右值），不能被赋值。[/quote] 那大神 能说说为什么 *(void  **)&  这种方式就能赋值了呢   感觉有点神奇。。[/quote] 因为 *p 是个左值啊 ...[/quote]  懂了  那除了这种还有 其他的指针赋值的方式吗 ？

user: user-3
content: 引用 10 楼 qq_34717051 的回复:[quote=引用 9 楼 fefe82 的回复:] [quote=引用 8 楼 qq_34717051 的回复:] [quote=引用 7 楼 fefe82 的回复:] 给程序。。。  下面是程序代码   下面 还有个动态模块  #include <stdio.h> #include <dlfcn.h>    int (*func)(int , int );  int main(int argc, char **argv) { 	int a = 5,b = 7; 	void *handle; 	if (!(handle = dlopen("./mymath.so", RTLD_NOW))) 			{ 				printf("11111111\n"); 			}  	 	(void *)(func) = dlsym(handle, "add");   //报错   	printf("%d\n", func(a,b));   	*(void **)(&func) = dlsym(handle, "sub");  	printf("%d\n", func(a,b)); 		  }   int add(int a,int b) { return (a+b); } int sub(int a,int b) { return (a-b); } [/quote]  (void *)(func) 强制类型转换结果是一个临时变量（右值），不能被赋值。[/quote] 那大神 能说说为什么 *(void  **)&  这种方式就能赋值了呢   感觉有点神奇。。[/quote] 因为 *p 是个左值啊 ...

user: user-0
content: 引用 9 楼 fefe82 的回复:[quote=引用 8 楼 qq_34717051 的回复:] [quote=引用 7 楼 fefe82 的回复:] 给程序。。。  下面是程序代码   下面 还有个动态模块  #include <stdio.h> #include <dlfcn.h>    int (*func)(int , int );  int main(int argc, char **argv) { 	int a = 5,b = 7; 	void *handle; 	if (!(handle = dlopen("./mymath.so", RTLD_NOW))) 			{ 				printf("11111111\n"); 			}  	 	(void *)(func) = dlsym(handle, "add");   //报错   	printf("%d\n", func(a,b));   	*(void **)(&func) = dlsym(handle, "sub");  	printf("%d\n", func(a,b)); 		  }   int add(int a,int b) { return (a+b); } int sub(int a,int b) { return (a-b); } [/quote]  (void *)(func) 强制类型转换结果是一个临时变量（右值），不能被赋值。[/quote] 那大神 能说说为什么 *(void  **)&  这种方式就能赋值了呢   感觉有点神奇。。

user: user-3
content: 引用 8 楼 qq_34717051 的回复:[quote=引用 7 楼 fefe82 的回复:] 给程序。。。  下面是程序代码   下面 还有个动态模块  #include <stdio.h> #include <dlfcn.h>    int (*func)(int , int );  int main(int argc, char **argv) { 	int a = 5,b = 7; 	void *handle; 	if (!(handle = dlopen("./mymath.so", RTLD_NOW))) 			{ 				printf("11111111\n"); 			}  	 	(void *)(func) = dlsym(handle, "add");   //报错   	printf("%d\n", func(a,b));   	*(void **)(&func) = dlsym(handle, "sub");  	printf("%d\n", func(a,b)); 		  }   int add(int a,int b) { return (a+b); } int sub(int a,int b) { return (a-b); } [/quote]  (void *)(func) 强制类型转换结果是一个临时变量（右值），不能被赋值。

user: user-4
content: 这样写可读性比较好： typedef  int (*Function)(int , int );  Function f;  f = (Function)dlsym(handle, "add"); printf("%d\n", f(a, b));  f = (Function)dlsym(handle, "sub"); printf("%d\n", f(a, b));

user: user-0
content: 引用 7 楼 fefe82 的回复:给程序。。。  下面是程序代码   下面 还有个动态模块  #include <stdio.h> #include <dlfcn.h>    int (*func)(int , int );  int main(int argc, char **argv) { 	int a = 5,b = 7; 	void *handle; 	if (!(handle = dlopen("./mymath.so", RTLD_NOW))) 			{ 				printf("11111111\n"); 			}  	 	(void *)(func) = dlsym(handle, "add");   //报错   	printf("%d\n", func(a,b));   	*(void **)(&func) = dlsym(handle, "sub");  	printf("%d\n", func(a,b)); 		  }    int add(int a,int b) { return (a+b); } int sub(int a,int b) { return (a-b); }

user: user-3
content: 给程序。。。

user: user-5
content: 引用 4 楼 qq_34717051 的回复:[quote=引用 2 楼 paschen 的回复:] (void *)  是将类型转换为void*  (void **)  是将类型转换为void**，再从指向的地址进行取值  如果你xxx是0x12345678  前者结果只是值为0x12345678的指针  后者是在0x12345678地址中的值  我的xxx是函数指针      具体是用在 动态加载模块函数 dlopen（）上      返回值 是void *  ，  （void *）xxx = dlopen（）这样 报错了  但是 *（void **）（&xxx） =  dlopen（）就能成功  ，难道不是直接把指针强制转换成（void *）才能成功吗 ？  不是很懂 。。[/quote]  dlopen返回值本来就是void*，你只是做类型转换又怎么可能报错

user: user-5
content: 引用 4 楼 qq_34717051 的回复:[quote=引用 2 楼 paschen 的回复:] (void *)  是将类型转换为void*  (void **)  是将类型转换为void**，再从指向的地址进行取值  如果你xxx是0x12345678  前者结果只是值为0x12345678的指针  后者是在0x12345678地址中的值  我的xxx是函数指针      具体是用在 动态加载模块函数 dlopen（）上      返回值 是void *  ，  （void *）xxx = dlopen（）这样 报错了  但是 *（void **）（&xxx） =  dlopen（）就能成功  ，难道不是直接把指针强制转换成（void *）才能成功吗 ？  不是很懂 。。[/quote]  是强制转换

user: user-0
content: 引用 2 楼 paschen 的回复:(void *)  是将类型转换为void*  (void **)  是将类型转换为void**，再从指向的地址进行取值  如果你xxx是0x12345678  前者结果只是值为0x12345678的指针  后者是在0x12345678地址中的值  我的xxx是函数指针      具体是用在 动态加载模块函数 dlopen（）上      返回值 是void *  ，  （void *）xxx = dlopen（）这样 报错了  但是 *（void **）（&xxx） =  dlopen（）就能成功  ，难道不是直接把指针强制转换成（void *）才能成功吗 ？  不是很懂 。。

user: user-0
content: 引用 1 楼 qq_36409192 的回复:void *表示的是一个无类型的指针，比如说NULL。 *（void **）表示的是将一指针其类型强行变为void **型。  你这里已经声明了XXX为一个指针，那么你在使用 void *很明显就是多次声明了。而*（void **）表示的则是将其类型进行了改变。  为什么  （void *）不是强制类型转换吗 。。

user: user-5
content: (void *)  是将类型转换为void*  (void **)  是将类型转换为void**，再从指向的地址进行取值  如果你xxx是0x12345678  前者结果只是值为0x12345678的指针  后者是在0x12345678地址中的值

user: user-6
content: void *表示的是一个无类型的指针，比如说NULL。 *（void **）表示的是将一指针其类型强行变为void **型。  你这里已经声明了XXX为一个指针，那么你在使用 void *很明显就是多次声明了。而*（void **）表示的则是将其类型进行了改变。