一
、一维数组,一级指针;二维数组,二级指针
1)指针和数组在使用上有类似性(比如a[5]可以访问数组中第六个元素,p+5同样也可以访问),但指针和数组是没有关系的,这是两种不同的类型。
2)指针可以做左值也可以做右值(可表示空间,可表示内容),数组只能做右值(可以将数组赋值给别的变量,但不能将变量直接赋值给数组)。
3)指针做右值表示它的内容,数组名做右值表示的是数组首元素的首地址。
4)只有sizeof(数组名),&数组名,这两种情况数组名代表整个数组,其他情况都代表首元素的地址。
二、数组指针、指针数组
指针数组是数组,是一个存放指针的数组,int *a[10]; --> a是一个数组,是一个存放指针的数组,是一个存放的指向整型的指针的数组
数组指针是指针,是一个指向数组的指针,int (*p)[10]; --> p是一个指针,是一个指向数组的指针,是一个指向含10个整型元素的数组的指针
三、指针和数组的定义和声明
定义分配内存,而声明没有。
1.定义为数组,声明为指针
文件1中定义如下:
zhar arr[100];
文件二声明如下:
extern char * a;
这是错误的,当你声明为extern *a时,编译器理所当然地认为a是一个指针变量,在32位系统下,占4字节。这4字节里保存了一个地址,这个地址上存储的是字符型数据。大多数编译器是按文件分别编译的,编译器只按照本文件声明的类型来处理。所以,虽然a实际大小为100字节,但是在文件2中,编译器认为a只占4字节。
2.定义为指针,声明为数组
文件一:
char *p="abcdefg";
文件2:
extern char p[];
文件1中,编译器分配4字节空间,并命名为p;同时p里保存了字符串常量“abcdefg”的首字符的首地址,这个字符串常量本身保存在内存的静态区,其内容不可更改。在文件2中,编译器认为p是一个大小为4字节的数组,数组内保存的是cha类型的数据。
![](https://i-blog.csdnimg.cn/blog_migrate/7a9877398742347239f948e8eaf30791.png)
四、数组指针参数
1)一维数组传参
无法向函数传递一个数组。
在C语言中,当一维数组作为函数参数的时候,编译器总是把他们解析成一个指向其首元素首地址的指针。
以下是正确的传参方式:
void test(int arr[])
{
}
void test(int arr[10])
{
}
void test(int *arr)
{
}
void test2(int *arr[20])
{
}
void test2(int **arr)
{
}
int main()
{
int arr[10];
int *arr2[20];
test(arr);
test2(arr2);
}
2)二维数组传参
void fun(char a[3][4]);
可以把
a[3][4]理解为一个一维数组a[3],其每个元素都是一个含有4个char类型数据的数组。根据上面一维数组的规则,我们可以把这个声明改写为:void fun(char (*p)[4]);这里的括号绝对不能省略,这样才能保证编译器把p解析为一个指向包含4个char类型数据元素,即一维数组a[3]。同样,
void fun(char a[ ][4]);也正确。但是第二维不可省略。
如果把上面提到的声明:void fun(char (*p)[4]);中的括号去掉之后,void fun(char *p [4]);可以改写成:void fun(char **p [4]);
3)一级指针传参
void test1(int *p) --> 此时p可以接收:整型数组、整型元素的地址
void test2(char *p) --> 此时p可以接收:字符数组、字符的地址、字符串
4)二级指针传参
void test(char **p) --> 此时p可以接收:二级指针、指针数组、一级指针的地址
数组指针、指针数组、函数指针、函数指针数组、指向函数指针的数组的指针在这里:点击打开链接
五、回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个函数被用来调用其所指向的函数时,我们说这是回调函数。
使用回调函数,模拟实现qsort
#include<stdio.h>
int int_cmp(const void * p1, const void * p2)
{
return (*(int *)p1 > *(int *)p2);
}
void _swap(const void * p1, const void * p2, int width)
{
int i = 0;
for (i = 0; i < width; i++)
{
char tmp = *((char *)p1 + i);
*((char *)p1 + i) = *((char *)p2 + i);
*((char *)p2 + i) = tmp;
}
}
void my_qsort(void *base, int sz, int width, int(*cmp)(void *, void *))
{
int i = 0;
int j = 0;
for (i = 0; i < sz - 1; i++)
{
for (j = 0; j < sz - 1 - i; j++)
{
if (cmp((char *)base + j*width, (char *)base + (j + 1)*width)>0)
{
_swap((char *)base + j*width, (char *)base + (j + 1)*width, width);
}
}
}
}
int main()
{
int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
int i = 0;
my_qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);
for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
printf("%d", arr[i]);
}
printf("\n");
system("pause");
return 0;
}