C语言中的指针


原文链接: 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
版权声明:本文为博主原创文章,转载请附上博文链接!

`