如何区分数组指针与指针数组,数组指针是指针。指针数组是数组。可以通过对他们的优先级进行比较。可以根据语句中的优先级来判断,()>[]>*,用下面的例子来说明区分这两种。
char * a[3]:这个优先级最高的a[3]所以是一个数组变量,然后就是数组的类型了,char *说明该类型是char类型指针,所以为指针数组。
char (*a)[3]:这个中()的优先级高下,所以是一个指针变量,然后再看类型为一个数组类型的,所以叫数组指针。
数组指针:数组指针是一个指向数组的指针。数组指针用于指向一个数组的起始地址,通常用于函数参数,以传递数组。
int arr[3] = {1, 2, 3}; // 一个包含3个整数的数组
int (*p)[3]; // 一个指向包含3个整数的数组的指针
p = &arr;
for (int i = 0; i < 3; i++) {
printf("%d\n", (*p)[i]);
}
下面是数组指针的运算,理解下面的代码,可以把二维数组看为一个一维数组,一维数组里的元素又是一个一维数组。要注意理解p+1与*(p+1),虽然地址是一样的,但是意义是不一样的。p+1是二维数组a[1]的首地址及a[1][0],进行++、--等运算时时移动(int)4*4(数组个数)个字节,而*(p+1)是,p+1到a[1]的地址下,对它进行解引用就为a[1][0]的地址,进行++、--运算时就移动4个字节,如*(p+1)+1即为a[1][1]的地址。
指针数组:指针数组是一个数组,其中每个元素都是指针。指针数组可以用来存储多个指针,例如指向字符串的指针。
char *arr[3]; // 一个包含3个指针的数组,每个指针指向一个字符(字符串)
arr[0] = "Hello";
arr[1] = "World";
arr[2] = "C Programming";
for (int i = 0; i < 3; i++) {
printf("%s\n", arr[i]);
}
指针指针:指针指针其实就是指针里的数据还是指针(地址),为什么要声明char **p呢、因为ch存的是地址、类型为char *,要个指针指向它的首地址,就应该是char *(ch的数据类型) *p(声明一个指针变量),所以就为char **p,对p解引用就是为ch每个字符串的首地址。
#include <stdio.h>
void sort2Str(char **p,int row){
for(int i=1;i<row;i++){
char *q = *(p+i);
int j = i;
while(j>0 && strcmp(*(p+j),*(p+j-1))<0){
*(p+j) = *(p+j-1);
j--;
}
*(p+j) = q;
}
}
int main(int argc, const char *argv[])
{
char* ch[] = {"hello","word"};//存放字符串常量中的首地址
char *ch1[]={"hello","word","adress","slop"};
char **p = ch;//指针的指针,二级指针
sort2Str(ch1,4);
for(int i=0;i<2;i++)
puts(*(p+i));
return 0;
}
指针函数:指针函数是指返回值为指针的函数。这意味着这个函数在被调用时,返回的是一个指针。下图中、getMax函数返回一个指向整数的指针。函数的返回值是指向a或b的指针,这取决于哪一个值更大。
int* getMax(int *a, int *b) {
if (*a > *b)
return a;
else
return b;
}
int main() {
int x = 10, y = 20;
int *max = getMax(&x, &y);
printf("Max value: %d\n", *max);
return 0;
}
函数指针(回调函数):函数指针是一个指向函数的指针。这意味着你可以通过函数指针来调用函数,就像调用普通函数一样。
函数指针的声明是:int (*p) (int a,int b)或int (*p) (int,int),声明一个函数指针,返回值为int、参数为2个int类型的数据。
函数调用:int ret = p(1,2)或(*p)(1,2)。其中(*p)中的*可以很多个(********p),但是编译器也不会去识别它,它只要函数的地址。
#include <stdio.h>
void sortArray(int *a,int n,int (*f)(int)){//接收f形参函数的地址、参数
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(f(a[i]) > f(a[j]) ){
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
}
int fun1(int n){
return n*n;
}
int fun2(int n){
return n*n*n;
}
int main(int argc, const char *argv[])
{
int a[8]={2,-1,4,3,-7,6,5,8};
sortArray(a,8,fun1);//函数名就是地址
for(int i=0;i<8;i++)
printf("%d ",a[i]);
putchar('\n');
return 0;
}
二、void*类型的指针
在C语言中,void *
是一种通用指针类型,可以指向任何类型的数据。与其他指针类型之间的转换关系比较特殊,因为void *
在指针类型之间的转换中有一些灵活性。下面详细介绍void *
与其他指针类型之间的转换关系,sizeof(void)=1。
1. void *
到其他指针类型的转换
void *
可以被隐式转换为任何其他类型的指针,而不需要显式的类型转换。例如:
int a = 10;
void *ptr = &a; // 隐式转换为void *
int *intPtr = ptr; // 需要显式转换为int *
虽然一些编译器允许这种隐式转换(从 void *
到其他类型的指针),但为了确保代码的清晰性和安全性,通常建议显式进行类型转换,如下所示:
int *intPtr = (int *)ptr; // 显式转换为int *
2. 其他指针类型到void *
的转换
其他类型的指针可以隐式地转换为void *
,而不需要显式的类型转换。这种转换是安全的,且符合C语言标准。
int a = 10;
int *intPtr = &a;
void *ptr = intPtr; // 隐式转换为void *
3. 注意事项
-
类型安全:
void *
的灵活性带来了一定的类型安全风险。转换不当可能导致未定义行为或程序崩溃。因此,在将void *
转换回其他类型的指针时,确保类型是正确的。 -
指针运算:不能对
void *
直接进行指针运算(如ptr++
),因为void *
不知道它指向的数据类型,也不知道步长(步长取决于指针指向的数据类型大小)。要进行指针运算,必须先将void *
转换为适当的类型指针
void *ptr = malloc(10 * sizeof(int)); // 分配内存给int数组
int *intPtr = (int *)ptr; // 转换为int *
intPtr++; // 现在可以进行指针运算