C语言中的指针
说透一级指针和二级指以及(void)&在双链表中的应用
注意char*是字符串指针,需要改变其对应的变量必须用地址,s1就是"abc"的起始地址,是不能被改变,要想改变s1必须用他的地址也就是&s1,所以需要void:
void swap(void *a, void *b)
{
void *t;
t =a;
a =b;
b=t;
}
int main()
{
char *s1="abc";
char *s2="def";
swap((void*)s1, (void*)s2);
关于(void)及其相关的理解#define LOADBASSFUNCTION (f) *((void **)&f)=(void*)GetProcAddress (hBass,# f)
这一句话使用*((void**)&f)
的原因在于,转化目标为左值(即转化f为void*类型(*)的函数指针)。
注意这里的(void)强制类型转换仅仅只是重新声明了指针解引用的方式,并没有提升指针的引用层级。意思上*((void)&f)与f是相等的(忽略(void)只看*&f就知道这本质上就是先取地址再解引用)。但是不能直接使用f,因为一个函数名不能做左值(要做左值必须指针化,也就是变成函数指针)。如果需要一个函数名直接做左值的话,需要将其转换为指针再取内容。实际上(void)可以被看成(void* *),后面的*表示函数被取地址后是一个指针,前面的void*表示这个指针被从新解释成了指向void*类型的指针(也就是相当于函数名被转换成了一个指针),之后对这个地址(&f)解引用,得到的自然就已经是一个函数指针了。
在hge中有这样一行代码:
#define LOADBASSFUNCTION(f) *((void)&f)=(void*)GetProcAddress(hBass,#f)
这是一个宏,作用是将任意函数指针f,都赋值成来自动态链接库的同名函数。右边使用的是(void*)指针做强制类型转换,这是一个通用的方法,不用担心具体函数签名是什么。
另外,只能使用函数指针来接收一个函数地址,无论是从动态库导出的函数。还是其他的函数。
注释:
(*)在c++中void*可以接收所有类型的指针,但是反之不可。在c中void*既可以赋值给任何指针,也可以被任何指针赋值
直接对物理地址0x5a000赋值
*((int *)0x5a0000) =0x01
将一个地址变成函数并调用
#define POWERDOWN(clk) ((void(*)(int))0x00000020)(clk)
int main(){
int addr; 定义一个变量用来存放地址
addr = (int)test; 将一个函数的入口地址转换成int 存入addr变量
((void(*)(int))addr)(0); //将int值转换成函数调用
((void(*)(void))addr)(); //直接调用
(*(void(*)(void))addr)(); //直接调用也OK
// 指针函数
void (*pfn)(int x);
}
1. 指针 *p++与(*p)++的区别
1.根据运算优先级,*与++时同一优先级,因此无法直接判定结合性,又由于一元运算符具有由右向左结合,因此*p++ 等价于*(p++),即先将指针后移,然后取值
2.(*p)++ 为先取当前p所指的值,然后所取值加1
int main(int argc, char** argv) {
int a[5]={0,1,2,3,4};
int *p = a;
cout<<*p++<<" "<<(*p)++<<endl;
cout<<a[0]<<endl;
cout<<*p<<endl;
return 0;
}
//1 0
1 1
cout从右往左算,先输出p所指向的a[0]的值,然后a[0]的值变为1 ,然后看*p++,p指针后移,取值为a[1],即1;
C语言中的指针和p, p+1, *(p+1), *P+1, p[0], &p[0] 每一种表达式的含义
一、先解决一个问题:什么是指针
指针就是存放地址的变量。很好,百度上就是这个答案(哈哈,感觉这句话很废话)。
指针是一个大小固定为4个byte的变量,不管是什么类型的指针大小都是固定的,因为存放是一个地址信息。
void main()
{
int a = 1;
char b = 'a';
int* i = &a;//指向一个int值变量
char* c = &b;//指向一个char值变量
}
从上面的程序中可以看出来,定义一个int类型的指针和char类型的指针,但它们的大小都是4byte,因为存放的是对应类型变量的地址而不是对应类型变量的内容。
二、指针P与指针P+1
void main()
{
int a[] = {1,2,3,4};
int* b = (int*)&a;
}
在上面的程序中定义一个int类型的指针(在这里要重点强调一下,这里是int类型的指针,对后面的内容的理解很重要),指针b的地址为0x0018ff38,指针b+1的地址为0x008ff3c,他们中间相隔了4byte,刚好是一个int类型的大小,而指针b又是一个int类型的指针,所以我们可以得出一个结论:
指针P+1 = 指针P + sizeof(指针的类型) * 1
三、数组和指针(刚好看到上面程序结果想到的一个点)
在上面的运行结果中,我们可以发现a[1]和*(p+1)得到的值是一样的,因为&a[1]指向的地址和P+1指向的地址是一致。
在C语言中获得数组的值有两种方法:
第一种:匿名方法 --> a[1]
第二种:具名+匿名方法 --> P + sizeof(数组类型)*1
四、*(P+1)和*P+1的不同之处
void main()
{
int a[] = {1,4,3,4};
int* p = (int*)&a;
}
其实这个问题很简单,因为*的优先级比+的优先级高,所以*P+1在编译器中是先取出p指向的int值然后加1,就是a[0]+1,也就是1+1,所以p+1取出的值等于2。而(P+1),因为多了一个括号,所以就变成指针P+1后,再取出里面的值,也就是a[1]的中的值,所以*(P+1)取出的值等于4。
五、*(P+1)和P[1]
也是用上面的程序,我直接上运行结果,一看就知道了
这大概是写法不同把,我个人的理解应该是跟上面第三点的两种取值方法原理相似。我做了以下的尝试
void main()
{
int a[] = {1,4,3,4};
}
可以正常运行,没有报错,这里就证明我的一个猜想,定义一个int类型的数组a,可以直接把a当做一个指向数组a首地址的int类型的指针使用。这就是说,定义一个int数组其实编译器内部开辟一个内存块和指向首地址int类型的指针给我们。
到这里,最后一个&P[0]的含义就很明显了,可以看成取数组第一元素的地址。
作者:一个有梦想的码农
来源:CSDN
原文:https://blog.csdn.net/m0_37605407/article/details/79198118
版权声明:本文为博主原创文章,转载请附上博文链接!