关于C语言中指针的总结

指针是c语言中十分重要的一环,也是最难理解的一个大知识点。以下是对指针知识点的一个总结梳理,便于后续复习理解。

一、初步了解指针

首先了解指针之前需要了解计算机是怎么工作的。
简单来说,就是CPU与内存之间的工作逻辑:
CPU从内存中读取数据,进行处理,然后放回内存里,而CPU需要精确找到所需要的数据,就需要内存对每个数据进行编号,而这些数据的编号就是地址。

1. 内存、地址、指针

如图所示,内存中的空间以这种方式排布,红色为申请的内存空间,白色的作为每个空间的编码,即地址
在c语言中,将内存中的地址定义为指针。而下图中,红色箭头就用来代表指针,其指向的是内存中的一块地址。指针可以根据需要,指向所需空间的地址。
内存中的地址与指针
而为了使用指针,我们还需要了解两种操作符——取地址操作符(&)解引用操作符(*)

2.取地址操作符(&)

首先我们知道,内存中的空间是需要申请的,那么就需要创建变量向内存申请使用空间。
当我们创建了一个变量后,内存中将根据这个变量的类型来其开辟一个大小的空间,例如int类型,就会申请4个字节大小的空间,每个字节都有属于自己的地址,如上一节中的图片所示。
现在我们需要获得这个地址,就需要用到取地址操作符(&)

int main ()
{
	int a = 10;
	 &a;
	 return 0;
}

如上面代码所示,取地址操作符(&) 将获得a变量的地址,因为a变量的类型是int类型,所以这里将有4个字节的内存空间,以及四个连续的地址。
取地址操作符(&) 将拿到4个字节中值最小的那个地址。

3.指针变量

现在我们获得了地址,那么地址该怎么用呢?
为了能方便使用地址,这里我们需要了解一个新的变量——指针变量

int* p = &a;

这里的代码就是指针变量p被a的地址赋值。
意思就是,在内存中再开辟一个空间(32位系统中其大小为4个字节,64位系统中其大小为8个字节),把内存的地址存在内存中,方便之后使用 (实现套娃)

指针变量的大小与数据类型无关。

之后怎么使用指针变量呢?这里就需要 解引用操作符(*)

4.解引用操作符(*)

==解引用操作符(*)==就是一个星符号,和双目操作符乘法符号长得一样,但用法不同。

*p = 0;

这里 *p 就是找到 指针变量p 的位置,获得这块空间的中存放的内容——a变量。
而这个 *p 可以隔空给变量a赋值。例如这个将a的值改成了0。
解引用操作符一次能修改几个字节,主要所对应指针的类型所决定的。

	char*		1个字节
	short*		2个字节
	int*		4个字节	
	float*		4个字节
	long long*	8个字节
	double*		8个字节

其中 void* 类型的指针最为特殊,作为一个临时仓库,其可以接收各类型指针变量, 但代价就是其不能参与指针的任何计算

5.const关键字

接下来我们了解一个控制指针变量的关键字—— const

int const* p;//const 放在*的左边做修饰
const int* p;//const 放在*的左边做修饰
int* const p;//const 放在*的右边做修饰

其使用方式如上面代码所示,放在代表指针的(*)符号的旁边,可以限制指针变量。
但放在不同的位置作用不一样:

放在星号左边:将指针指向的地址里存放的变量值锁定,无法解引用修改变量值,但可以指向的其余的地址。
放在星号右边:将指针指向的地址本身锁定,但可以改变该地址中存放的变量值。
*p = 20; //放左边不能改,放右边可以改
 p = &m; //放右边不能改,放左边可以改

既然可以修改指针变量,那么围绕其的运算方式肯定不能少。

6.指针的运算方式

1)指针±整数

计算方式例如:

p + i ;//是跳过  i * sizeof(类型) 

指针变量p是什么类型就能走* i × sizeof(类型) *远的距离。
例如数组在内存中是连续存放的,那么我们可以通过数组中的元素地址,找到其他的元素。

int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = arr;
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0]);
for(i=0; i<sz; i++)
 {
	 printf("%d ", *(p+i));
 }

这里的 i 的值就是整型,整型变量p就可以一次增加4个字节,即一个数组元素。

2)指针-指针

计算方式例如:

char *s = a;
char *p = s;
 p-s;

这里指针减去指针的绝对值是指针和指针之间的元素个数,但有一个重要的前提——两个指针指向的时同一块空间!

为什么没有指针+指针呢?
因为指针-指针本质上就是一个空间内,两个不同指针之间的距离。
例如a的qq等级一个太阳,b的qq等级三个月亮,你可以说他两之间qq等级差一个月亮(4个月亮升级为1个太阳),但不存在第三个人的情况下,两个人的等级加起来等于一个太阳三个月亮有意义吗?这个值也无法赋予给任何单位,所以指针+指针同理。

3)指针比大小

比较方式如下:

int *p = &arr[0];
if(p < &arr[sz])
{
	return 1;
}

这里比较的其实就是两个指针不同的地址的值的大小。可以用判断两个指针之间在内存中 谁在上谁在下的 位置关系。

7.野指针

初步了解怎么写正确的指针变量后,我们也需要了解怎么防止错误的指针变量。
这里就需要提到一个概念—— 野指针
野指针的意思是,其指针指向了一个不该存在的、没有被规定的位置。其位置是不可知不可控的。
那么我们该怎么防止写出这样的错误代码呢?
第一步就需要将指针初始化,例如:

int*p1 = &num;
int*p2 = NULL;

这里NULL的意思就是0,但指针这样初始化后是不可以解引用的。

第二步,检查自己的代码有没有写错,防止指针越界访问。
第三步,不要让野指针返回一个被内存释放掉的局部变量内。
第四步,在检查无误后,对不适用的指针进行NULL赋值,防止指针变成脱缰的野马到处奔腾!

但代码写久了就会头昏眼花,十分恼火,一时发现不了指针哪里错误了,这时候就可以用 asser关键字

这个关键字被称为“断言”,俺觉得不如命名为“青天大老爷”更为合适
因为其可以检查条件是否为真,例如:

#include <assert.h>
assert(p != NULL);

asser关键字需要一个头文件assert.h

我们这里判断p不为空指针,那么“断言”就会判断条件是否为真,为真运行程序,为假直接报错,还会告诉你在哪“犯法”了。
很方便的是,当你不需要它的时候,你可以直接一行NDEBUG代码关闭它,不需要在几百行的代码中寻找这个句子。

#define NDEBUG

8.传值调用和传址调用

传值调用:把变量本身的值直接传递给了其他函数。
在调用函数时,实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实参。
虽然很方便,但是存在一个问题,传过去的值不能实现更改,只能计算。
那么就需要一个新方法“传址调用”。

顾名思义!传递地址。
传址调用:是将变量的地址传递给了函数。
我们最初了解到,可以隔空通过*p更改变量a的值,那么这里也是同理的,直接修改其地址,通过地址找到对应变量值来达到修改目的。

二、指针与数组

首先我们知道,数组名是数组首元素的地址,但有两个例外。

sizeof(数组名) :只要sizeof内单独存放了一个数组名,那么这个数组名表示整个数组,sizeof就会计算这整个数组的大小,单位字节。

&数组名 : 取地址操作符后跟数组名,表示整个数组,取地址操作符将会取出整个地址的数组。

1.指针访问数组

直到上面的基础知识,我们就可以这样用指针对数组进行访问和使用:

int arr[10] = {0};
int* p = arr;
printf("%d ", *(p+1));//*(p+1) == p[1] == *(arr+1) == arr[1]
printf("%d ", parr[i][j]);//相当于 *(*(arr+i)+j)

//⼀维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。
void test(int arr[]);
void test(int* arr);

2.二级指针

二级指针也是指针,可以用来存放指针的地址,实现俄罗斯套娃。
如下代码:

int b = 20;
int *p = &b;
int* *pa = &p;

这里指针变量 p中存放了 b的地址,而二级指针 pa中存放了 p的地址。
*p就是一级指针,指向的类型是 int;
**p就是二级指针,指向的类型是int *。
一级指针可以解引用获得指向的内容,二级指针同样可以:

**ppa = 10;

这里相当于将 b 的值改成了30。

3.指针数组与数组指针

1)指针数组

指针数组 顾名思义,是存放指针的数组,其每个元素都是存放指针(地址)的。
我们可以利用这点实现模拟二维数组:

int arr1[] = {1,2,3,4,5};
int arr2[] = {2,3,4,5,6};
int arr3[] = {3,4,5,6,7};
int* parr[3] = {arr1, arr2, arr3};

这里就相当于用一个指针数组存放了三个数组名,即三个不同数组的首元素地址。

2)数组指针

数组指针 是一种变量,即指针变量,是用来存放数组的地址,可以指向数组的指针变量。

int* p1[10];//指针数组
int (*p2)[10];//数组指针

看上面代码就能发现,指针变量名先跟谁就是谁的变量,上面有限跟的[10],所以是一个数组,下面先跟的*,所以是一个指针。

数组指针的初始化方式如下:

int (*p) [10] = &arr;
 |    |    |
 |    |    |
 |    |    p指向数组的元素个数
 |    p是数组指针变量名
 p指向的数组的元素类型

4.字符指针

char* 是字符指针。

char ch = 'w';
char *p1 = &ch;
*pc = 'w';
char* p2 = "hello bit.";
char* p3 = "hello bit.";

这里赋值不是把字符或字符串存在指针里了,而是指针指向了字符或字符串所在的空间,将其首字符的地址存存放进 p1、p2 和 p3 里了。同时也意味着 p2 和 p3 指向的是同一块空间,那么他们存放的地址也是一样的。

5. 二维数组传参

我们知道,组名是首元素地址。一维数组在传参的时候,其实传递的是首元素地址,函数的参数可以写成数组,也可以写成指针。

那么二维数组呢?
其实二维数组的数组名也是数组首元素的地址,二维数组的每一行可以看做是一个一维数组,所以二维数组其实是一个一维数组的数组,二维数组的首元素,就是他的第一行。

⼆维数组传参的时候,形参的部分可以写成数组,也可以写成指针形式。

void test(int (*p)[5], int r, int c)
void test(int arr[3][5], int r, int c)

int main()
{
 int arr[3][5] = {{1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7}};
 test(arr, 3, 5);
 return 0;
}

6.函数指针

函数指针是存放函数地址的。

函数是有地址的,函数名就是函数的地址,当然也可以通过==&函数名==的⽅式获得函数的地址。

int (*pf3) (int x, int y)
 |     |    ------------ 
 |     |         |
 |     |         pf3指向函数的参数类型和个数的交代
 |     函数指针变量名
 pf3指向函数的返回类型
int (*) (int x, int y) //pf3函数指针变量的类型

怎么调用函数指针呢?

int Add(int x, int y)
{
 return x+y;
}

int main()
{
 int(*pf3)(int, int) = Add;
 printf("%d\n", (*pf3)(2, 3));
 printf("%d\n", pf3(3, 5));
 return 0;
}

如上代码,(*pf3)(2, 3) 和 pf3(3, 5) 都是在调用函数,或者说解引用。
不过函数名本身就是地址,可以不写 * 解引用,写了看起来更容易理解,如果要带上 * ,就用得括号括起来。

7.typedef 关键字

现在看着这些指针变量就头疼,又长又难记,那么我们就可以用typedef关键字来帮助我们对类型进行重命名。例如:

typedef int* pa;
typedef int(*pb)[5]; 

这里将 整型指针 和 数组指针 都重命名为 pa 和 pb 了。

8.函数指针数组

函数指针数组 指把函数的地址存到⼀个数组中,

int (*parr1[3])();//int (* 数组名[ 数字 ]  )(int ,int ) = {函数名1,函数名2}

函数指针数组的⽤途——转移表。

int add(int a, int b)
int sub(int a, int b)
int mul(int a, int b)
int div(int a, int b)

int main()
{
	int(*p[5])(int x, int y) = { 0, add, sub, mul, div };
 	(*p[input])(x, y);
}

这里就是用函数指针数组实现跳转。

三、深入理解指针

1.回调函数

回调函数就是⼀个通过函数指针调⽤的函数。
或者这样表述:通过函数指针调用函数地址,被调用的那个函数就是回调函数。

回调函数不是由该函数的实现⽅直接调⽤,⽽是在特定的事件或条件发⽣时由另外的⼀⽅调⽤的,⽤于对该事件或条件进⾏响应。
非常抽象的句子,这样说可能更简单:函数A通过函数B调用函数C,函数B中的函数指针调用函数C,把C传给A。
回调函数

这里红色箭头指向的就是回调函数C。

2. qsort函数

qsort函数 是c语言中的一个库函数,这个函数是用来对数据进行排序的,可以对任意类型的数据进行排序,默认是升序。
qsort函数底层使用的是快速排序的方式。

void Print_int(int* arr, size_t sz)
{
	printf("int类型顺序是升序: ");
	for (int i = 0;i < sz;i++)
	{
		printf("%d ", arr[i]);
	}
}
int cmp_int(const void* x,const void* y)
{
	return *(int*)x - *(int*)y;
}
void test1()
{
	int arr1[] = { 9,8,7,6,5,4,3,2,1,0 };
	size_t sz = sizeof(arr1) / sizeof(arr1[0]);
	qsort(arr1,sz,sizeof(arr1[0]),cmp_int);
	Print_int(arr1, sz);
	
int main()
{
	test1();
	return 0;
}

这里qsort函数 需要四个形参:

void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))

base: 指向待排序数组的第一个元素的指针。
nitems: 数组中的元素数量。
size: 数组中每个元素的大小(以字节为单位)。
compar: 比较函数的指针,该函数用于比较两个元素。比较函数应当返回一个整数,表示比较结果:
小于零:表示第一个元素小于第二个元素。
等于零:表示两个元素相等。
大于零:表示第一个元素大于第二个元素。

3.sizeof和strlen的对⽐

sizeof和strlen的对比

四、实践指针

ok,深入了解指针之后,我们保存一系列实战练习的题目。

1.判断大小

第一题

void test1()
{
	char arr1[3] = { 'a', 'b', 'c' };
	char arr2[] = "abc";
	printf("test1: %zd\n", strlen(arr1));
	printf("test1: %zd\n", strlen(arr2));
	printf("test1: %zd\n", sizeof(arr1));
	printf("test1: %zd\n", sizeof(arr2));
}

第二题

void test2() 
{
	int a[] = { 1,2,3,4 };
	printf("test2: %zd\n", sizeof(a));
	printf("test2: %zd\n", sizeof(a + 0));
	printf("test2: %zd\n", sizeof(*a));
	printf("test2: %zd\n", sizeof(a + 1));
	printf("test2: %zd\n", sizeof(a[1]));
	printf("test2: %zd\n", sizeof(&a));
	printf("test2: %zd\n", sizeof(*&a));
	printf("test2: %zd\n", sizeof(&a + 1));
	printf("test2: %zd\n", sizeof(&a[0]));
	printf("test2: %zd\n", sizeof(&a[0] + 1));
}

第三题

void test3()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%zd\n", sizeof(arr));
	printf("%zd\n", sizeof(arr + 0));
	printf("%zd\n", sizeof(*arr));
	printf("%zd\n", sizeof(arr[1]));
	printf("%zd\n", sizeof(&arr));
	printf("%zd\n", sizeof(&arr + 1));
	printf("%zd\n", sizeof(&arr[0] + 1));
}

第四题

void test4()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%zd\n", strlen(arr));
	printf("%zd\n", strlen(arr + 0));
	printf("%zd\n", strlen(*arr));
	printf("%zd\n", strlen(arr[1]));
	printf("%zd\n", strlen(&arr));
	printf("%zd\n", strlen(&arr + 1));
	printf("%zd\n", strlen(&arr[0] + 1));
}

第五题

void test5()
{
	char arr[] = "abcdef";
	printf("%zd\n", sizeof(arr));
	printf("%zd\n", sizeof(arr + 0));
	printf("%zd\n", sizeof(*arr));
	printf("%zd\n", sizeof(arr[1]));
	printf("%zd\n", sizeof(&arr));
	printf("%zd\n", sizeof(&arr + 1));
	printf("%zd\n", sizeof(&arr[0] + 1));
}

第六题

void test6()
{
	char arr[] = "abcdef";
	printf("%zd\n", strlen(arr));
	printf("%zd\n", strlen(arr + 0));
	printf("%zd\n", strlen(*arr));
	printf("%zd\n", strlen(arr[1]));
	printf("%zd\n", strlen(&arr));
	printf("%zd\n", strlen(&arr + 1));
	printf("%zd\n", strlen(&arr[0] + 1));
}

第七题

void test7()
{
	char* p = "abcdef";
	printf("%zd\n", sizeof(p));
	printf("%zd\n", sizeof(p + 1));
	printf("%zd\n", sizeof(*p));
	printf("%zd\n", sizeof(p[0]));
	printf("%zd\n", sizeof(&p));
	printf("%zd\n", sizeof(&p + 1));
	printf("%zd\n", sizeof(&p[0] + 1));
}

第八题

void test8()
{
	char* p = "abcdef";
	printf("%zd\n", strlen(p));
	printf("%zd\n", strlen(p + 1));
	printf("%zd\n", strlen(*p));
	printf("%zd\n", strlen(p[0]));
	printf("%zd\n", strlen(&p));
	printf("%zd\n", strlen(&p + 1));
	printf("%zd\n", strlen(&p[0] + 1));
}

第九题

void test9()
{
	int a[3][4] = { 0 };
	printf("%zd\n", sizeof(a));
	printf("%zd\n", sizeof(a[0][0]));
	printf("%zd\n", sizeof(a[0]));
	printf("%zd\n", sizeof(a[0] + 1));
	printf("%zd\n", sizeof(*(a[0] + 1)));
	printf("%zd\n", sizeof(a + 1));
	printf("%zd\n", sizeof(*(a + 1)));
	printf("%zd\n", sizeof(&a[0] + 1));
	printf("%zd\n", sizeof(*(&a[0] + 1)));
	printf("%zd\n", sizeof(*a));
	printf("%zd\n", sizeof(a[3]));
}

2.指针运算结果

第一题

//程序的结果是什么?
void test10()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int* ptr = (int*)(&a + 1);
	printf("%d,%d", *(a + 1), *(ptr - 1));
}

第二题

//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结果是啥?
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p = (struct Test*)0x100000;
void test11()
{
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);
}

第三题

void test12()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	int* p;
	p = a[0];
	printf("%d", p[0]);
}

第四题

//假设环境是x86环境,程序输出的结果是啥?
void test13()
{
	int a[5][5];
	int(*p)[4];
	p = a;
	printf("%p,%zd\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
}

第五题

void test14()
{
	int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int* ptr1 = (int*)(&aa + 1);
	int* ptr2 = (int*)(*(aa + 1));
	printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
}

第六题

void test15()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);
}

第七题

void test16()
{
	char* c[] = { "ENTER","NEW","POINT","FIRST" };
	char** cp[] = { c + 3,c + 2,c + 1,c };
	char*** cpp = cp;
	printf("%s\n", **++cpp);
	printf("%s\n", *-- * ++cpp + 3);
	printf("%s\n", *cpp[-2] + 3);
	printf("%s\n", cpp[-1][-1] + 1);
}

3.函数模拟实现题目

模拟strlen

//模拟实现库函数strlen
size_t my_strlen(const char* arr)
{
	char* a = arr;
	while (*arr)
	{
		arr++;
	}
	return arr - a;
}

int main()
{
	char arr[] = {"0123456789"};
	size_t sz = my_strlen(arr);
	printf("%zd\n", sz);
	return 0;
}

冒泡排序

void bubble_sort(int arr[], int sz)//参数接收数组元素个数
{
	 int i = 0;
	 for(i=0; i<sz-1; i++)
	 {
		 int flag = 1;//假设这⼀趟已经有序了
		 int j = 0;
		 for(j=0; j<sz-i-1; j++)
		 {
		 	if(arr[j] > arr[j+1])
			 {
				 flag = 0;//发⽣交换就说明,⽆序
 				 int tmp = arr[j];
				 arr[j] = arr[j+1];
				 arr[j+1] = tmp;
	 		}
	 	 }
 	 	 if(flag == 1)//这⼀趟没交换就说明已经有序,后续⽆序排序了
			 break;
	   }
}
int main()
{
 	int arr[] = {3,1,7,5,8,9,0,2,4,6};
 	int sz = sizeof(arr)/sizeof(arr[0]);
 	bubble_sort(arr, sz);
 	int i = 0;
 	for(i=0; i<sz; i++)
 	{
 		printf("%d ", arr[i]);
 	}
 	return 0;
}

模拟二维数组

int main()
{
	int arr1[] = {1,2,3,4,5};
 	int arr2[] = {2,3,4,5,6};
	int arr3[] = {3,4,5,6,7};
 	int* parr[3] = {arr1, arr2, arr3};
	int i = 0;
	int j = 0;
	for(i=0; i<3; i++)
	{
		for(j=0; j<5; j++)
		 {
			 printf("%d ", parr[i][j]);
		 }
			 printf("\n");
		 }
	return 0;
}

计算器的实现

//课堂中转移表代码实践:将课堂上所讲使用函数指针数组实现转移表的代码
void menu()
{
	printf("************************\n");
	printf("*******整数计算器*******\n");
	printf("******* 1.  +    *******\n");
	printf("******* 2.  -    *******\n");
	printf("******* 3.  *    *******\n");
	printf("******* 4.  /    *******\n");
	printf("******* 0. exit  *******\n");
	printf("************************\n");
}
int Add(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}
int main()
{
	int input = 0;
	int (*p[5])(int, int) = { 0,Add,Sub,Mul,Div };
	int x = 0;
	int y = 0;
	do
	{
		menu();
		printf("请选择: ");
		scanf("%d", &input);
		if (input <=4 && input >=1)
		{
			printf("输入两个数: ");
			scanf("%d %d", &x, &y);
			int ret = p[input](x, y);
			printf("答案= %d\n", ret);
		}
		else if(input == 0)
		{
			printf("END\n");
		}
		else
		{
			printf("error\n");
		}	
	} while (input);
	return 0;
}

qsort函数的模拟实现(采⽤冒泡的⽅式)。

//模仿qsort的功能实现一个通用的冒泡排序
int cmp_int(const void* p1,const void* p2)
{
	return *(int*)p1 - *(int*)p2;
}
int cmp_char(const void* x, const void* y)
{
	return *(char*)y - *(char*)x;
}
void turn(char* p1, char* p2, size_t len)
{
	for (int i = 0;i < len;i++)
	{
		char tmp = *p1;
		*p1 = *p2;
		*p2 = tmp;
		p1++;
		p2++;
	}
}
void my_qsort(void* arr, size_t sz, size_t len, int(*cmp)(const void*, const void*))
{
	for (int i = 0;i < sz-1;i++)
	{
		for (int j = 0;j < sz - 1 - i;j++)
		{
			if (cmp((char*)arr+j*len , (char*)arr+(j+1)*len) > 0)
			{
				turn((char*)arr + j * len, (char*)arr + (j + 1) * len, len);
			}
		}
	}
}
void Print_arr(int* arr, size_t sz)
{
	for (int i = 0;i < sz;i++)
	{
		printf("%d ", arr[i]);
	}
}
void Print_char(char* arr, size_t sz)
{
	for (int i = 0;i < sz;i++)
	{
		printf("%c ", arr[i]);
	}
}
void test1()
{
	int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
	size_t sz = sizeof(arr) / sizeof(arr[0]);
	my_qsort(arr, sz, sizeof(arr[0]), cmp_int);
	Print_arr(arr, sz);
}
void test2()
{
	char arr2[] = {"1234567890"};
	size_t sz = sizeof(arr2)/sizeof(arr2[0]);
	qsort(arr2, sz, sizeof(arr2[0]), cmp_char);
	Print_char(arr2, sz);
}
int main()
{
	test1();
	//test2();
	return 0;
}
  • 25
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值