qsort函数的使用

使用qsort函数
int cmp(const char* e1, const char* e2)
{
return *((int*)e2) - (*(int*)e1);
}
void print(int* arr,int sz)
{
int i = 0;
for (i = 0;i < sz; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9 };
int sz = sizeof(arr)/sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp);//cmp表示另外一个函数
数组 元素个数 单个元素的大小 比较数组中相邻连个元素的大小
print(arr,sz);
return 0;
}

qsort函数的制造

struct stu
{
char name[20];
int number;
};

//比较int类型
int arrint_cmp(const void* e1, const void* e2)
{
return *(int*)e2 - *(int*)e1;
}

//比较结构体类型中的字符串
int struct_strcmp(const void* e1, const void* e2)
{
return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
//这里形参时整个分支,但是在比较的时候,只用其中一个分支的某一个变量
//这利用的就是name,以为是一个字符串,所以只比较首个字符的大小
}

//比较结构体中的数字
int struct_intcmp(const void* e1, const void* e2)
{
return ((struct stu*)e1)->number - ((struct stu*)e2)->number;
}

//交换函数
void swap(char* a,char*b, int width)
{
int i = 0;
for (i = 0;i < width;i++)
{
char tmp = *a;
*a = *b;
*b = tmp;
a++;
b++;
}
}

//写的qsort
void my_qsort(void* arr,int sz,int width,int(*p)(void*,void*))
{
int i = 0, j = 0;
for (i = 0;i < sz - 1;i++)//循环次数
{
for (j = 0;j < sz - 1 - i;j++)//进行的各个交换
{
if ((*p)(((char*)arr+j*width),((char*)arr + (j+1) * width)) > 0)
//在这里只是判断这个返回值的大小,里面的函数传结构体的时候,将结构体中的一整个分支都传过去
{
//在比较收个字符大小之后,再将两个分支传递给交换函数,将整个分支进行交换
swap(((char*)arr + j * width), ((char*)arr + (j+1) * width),width);
}
}
}
}

//打印函数
void print(int* arr, int sz)
{
int i = 0;
for (i = 0;i < sz; i++)
{
printf("%d ", arr[i]);
}
}

//按结构体中的两种不同类别经i性能排序
void struct_str_text()
{
struct stu s[3] = { {"zhangsan",20},
{"lisi",19},
{"wangwu",18} };
int sz1 = sizeof(s) / sizeof(s[0]);
//按字符串排序
//my_qsort(s, sz1, sizeof(s[0]), struct_strcmp);
//按数字排序
my_qsort(s, sz1, sizeof(s[0]), struct_intcmp);
//printf("%s ", s.number);

}

//按数组进行排序
void arr_int_text()
{
int arr[] = { 1,2,3,4,5,6,7,8,9 };

int sz = sizeof(arr) / sizeof(arr[0]);
my_qsort(arr, sz, sizeof(arr[0]), arrint_cmp);//cmp表示另外一个函数
// 数组 元素个数 单个元素的大小 比较数组中相邻连个元素的大小
print(arr, sz);

}
//主函数调用
int main()
{
//arr_int_text();
struct_str_text();

return 0;
}

指针深度理解

int main()
{
/*int arr[] = { 1,2,3,4,5,6,7 };*/

printf("%d\n", sizeof(arr));// 28 这里的arr是整个数组的地址,计算的也是整个数组中所有元素的地址字节总和,int类型4*个数7==28
printf("%d\n", sizeof(arr+0));//4 这里代表的是首元素的地址+0还是首元素的地址,地址是4字节
printf("%d\n", sizeof(*arr));// 4 这里还是首元素的地址,取内容得到1由于是int类型得到4
printf("%d\n", sizeof(arr[1]));//4 同上,但是得到的是第二个元素的值
printf("%d\n", sizeof(arr+1));//4

printf("%d\n", sizeof(&arr));//4 这里是整个元素的地址,无论是谁都是4/8
printf("%d\n", sizeof(&arr+1));//4 同上,但是跳过了整个数组
printf("%d\n", sizeof(*&arr));//28,可以想象成两个符号相抵消,int类型4*个数7==28
printf("%d\n", sizeof(&arr[0]));//4
printf("%d\n", sizeof(&arr[0]+1));//第一个元素的地址,跳过类一个数组

char arr1[] = { 'a','b','c','d' };
printf("%d ", sizeof(arr1));//4 这里是
上下两种意思不同,上面的是个数乘以类型字节
下面的意思是地址
printf("%d ", sizeof(arr1+1));//3////这的意思是首元素地址,+1跳还是地址
printf("%d ", sizeof(*arr1));//1
printf("%d ", sizeof(arr1[1]));//1
printf("%d ", sizeof(&arr1));//4
printf("%d ", sizeof(&arr1 + 1));//4
printf("%d ", sizeof(&arr1[0] + 1));//4

char arr1[] = { 'a','b','c','d' };
//strlen函数是接受的一个地址
printf("%d ", strlen(arr1));//sui
printf("%d ", strlen(arr1 + 1));// sui
printf("%d ", strlen(*arr1));//err
printf("%d ", strlen(arr1[1]));//err
printf("%d ", strlen(&arr1));//sui
printf("%d ", strlen(&arr1 + 1));//sui
printf("%d ", strlen(&arr1[0] + 1));//sui

char arr1[] = "abcd";
//&arr1就是整个地址,跳的话也是整个地址
//strlen函数是接受的一个地址
printf("%d ", strlen(arr1));//4
printf("%d ", strlen(arr1 + 1));//3
//printf("%d ", strlen(*arr1));//err
//printf("%d ", strlen(arr1[1]));//err
printf("%d ", strlen(&arr1));//4
printf("%d ", strlen(&arr1 + 1));//sui
printf("%d ", strlen(&arr1[0] + 1));//3

/*char* p="abcd";char* p="abcd";*/
printf("%d ", sizeof(p));//4 这里是地址
printf("%d ", sizeof(p + 1));//4
printf("%d ", sizeof(*p));//1//这里是首元素的地址,取内容是a,类型是char
printf("%d ", sizeof(p[1]));//1
printf("%d ", sizeof(&p));//4
printf("%d ", sizeof(&p + 1));//4
printf("%d ", sizeof(&p[0] + 1));//4

char* p = "abcd";
printf("%d\n", strlen(p));//4
printf("%d\n", strlen(p+1));//3
//printf("%d\n", strlen(*p));//err
//printf("%d\n", strlen(p[1]));//err
printf("%d\n", strlen(&p));//sui
printf("%d\n", strlen(&p+1));//sui
printf("%d\n", strlen(&p[0]+1));//3

int a[3][4] = { 0 };
printf("%d\n", sizeof(a));//3*4*4
printf("%d\n", sizeof(a[0][0]));//4
printf("%d\n", sizeof(a[0]));//16//二维数组第一个元素,是整个第一个二级数组,sizeof(int)*列
printf("%d\n", sizeof(a[0]+1));//4,地址
printf("%d\n", sizeof(*(a[0] + 1)));//4,类型大小
printf("%d\n", sizeof(a + 1));//4,地址
printf("%d\n", sizeof(*(a + 1)));//16//这里的a是二维数组首元素地址即整个二级数组的地址在取内容
printf("%d\n", sizeof(&a[0]+1));//4
printf("%d\n", sizeof(*(&a[0] + 1)));//16
printf("%d\n", sizeof(*a));//16
printf("%d\n", sizeof(a[3]));//16
//任何一个表达式都有两个表达式1、值属性2、类型属性
// sizeof(a[3])这里是用类型属性计算出来的
//sizeof()括号里面的是不会真正去计算的

return 0;
}

总结

:再求这种题的时候只有两种特殊情况

1、sizeof(arr)这里求的是整个元素占多少字节

2、&arr这里求的是整个数组的地址+1跳的也是真个数组

强制类型转换时的指针

struct text
{
char name[10];
}*p;
int main()
{
printf("%d\n", p);//
printf("%d\n", p + 0x1);//p的类型是指针+1跳过了一整个数组
printf("%d\n", (unsigned int)p + 0x1);//转换成了unsigned int 加1就是+1
printf("%d\n", (unsigned int*)p + 0x1);
//这里转换成了unsigned int*+1就是跳过了unsigned int*的步长
return 0;
}
int main()
{
//这里是小端存储(小端的一边数字权重比较小)
//所以我们按左端是小端而右边是大端

int arr[] = { 1,2,3,4 };//00 00 00 00
int* prt = (int*)(&arr + 1);
int* prt1 = (int*)((int)arr + 1);

printf("%x\n",prt[-1]);//4 //指针先以整个数组的大小进行跳跃,跳到最后,再转换成int*类型-1向后跳跃4个字节,在以16进制进行读取
//00 00 00 01|00 00 00 02|00 00 00 03|00 00 00 04|先跳到最后面在转换成int*-1向后移动1个int*的步数,在往后面读取

//地址里本来就是16进制进行储存的,打印的话格式按照16进制才能打印出来
printf("%x\n",prt1[0]);
//2 00 0000 这里先把数组首元素地址转换成int类型在+1就是一个字节,再转换成int*类型向后读取4个字节里面的内容,那个2就在读取的最后一个字节里面
//01 00 00 00|02 00 00 00|03 00 00 00|04 00 00 00|
// |00 00 00 02|加一就像后面移动了1位读取后的结果,
//在字节内中读取的时候是从左向右即从地址小的地方开始读取

//在地址里面,每一次以int类型+1,就相当于跳跃一个char*类型
//因为每一个地址对应一个字节
//1个字节8位,每四位也就是总共15是一个字节 00 ,两位中的其中一位
return 0;
}
int main()
{
int a[5][5];
int(*p)[4];
p = a;
printf("%p\n%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
//这里的的负数存在内存中的时候,是存的-4,读取的时候是-4但是在以16进制打印的是偶
printf("%d\n", sizeof(&p[4][2] - &a[4][2]));
return 0;
}

C语言指针进阶2_补码

int main()
{
int arr[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
int* ptr1 = (int*)(&arr + 1);
//整个数组的地址+1跳过整个数组,再转换成int*,-1后退一个int类型即4个字节就是10
int* ptr2 = (int*)(*(arr + 1));
//首元素的地址+1跳过一个二级数组,换成int*-1,后退一个int类型即4个字节就是5
printf("%d %d", *(ptr1 - 1), *(ptr2 - 1));
return 0;
}

数据结构的知识补充

int main()
{
char a = 128;
printf("%u", a);
printf("%d", a);
printf("%p", a);
//1、内存里面存的是什么
//2、打印的时候按什么格式打印的

//村进入内存的时候是10000000
//以16进制打印
//在以16进制打印的时候不会再转换成原码,而是直接以补码形式打印

//有符号形式打印
//11111111 11111111 11111111 10000000
//10000000 00000000 00000000 01111111
//10000000 00000000 00000000 10000000

//无符号形式打印
//00000000 00000000 00000000 10000000
//11111111 11111111 11111111 01111111
//11111111 11111111 11111111 10000000
return 0;
}
int main()
{
int a = -128;
printf("%u\n", a);
//10000000 00000000 00000000 10000000
//11111111 11111111 11111111 01111111
//11111111 11111111 11111111 10000000(存进去)(补码)
//以无符号形式打印,会直接打印补码(对于无符号整形就是正数),不会再转化成原码就是补码

printf("%d\n", a);
//10000000 00000000 00000000 10000000
//11111111 11111111 11111111 01111111
//11111111 11111111 11111111 10000000(存进去)(补码)
//10000000 00000000 00000000 01111111
//10000000 00000000 00000000 10000000(原码打印)-128
printf("%p\n", a);
//00000000 00000000 00000000 10000000
//11111111 11111111 11111111 01111111
//11111111 11111111 11111111 10000000(存进去)(补码)
//直接补码打印
return 0;
}

指针指向多个字符串的数组

int main()
{
char* arr[] = { "abc","at","bgv" };//本句的意思是arr是一个数组,里面存放的是char*类型的元素
//所以数组里面存放的都是三个元素的首地址,arr可以看作成二级数组

char** p = arr;
//arr是数组首元素的地址,将数组首元素的地址(首元素存放的还是一个地址,关于字符串的),存放到p里面,所以p就是char**
//由此可以看出,可以根据指针的类型判断出所指向的元素的类型

p++;//p是首元素的地址,p++,就是首元素地址+1
printf("%s", *p);//p取内容,第二个元素的地址取内容,就是第二个字符串
return 0;
}

1、指针在定义的时候,一共有几颗星,解引用(几-1)次,就可以得到内容

2、在指针定义的过程中,完全可以在脑海中补引入第三个盒子,相当于,把所要只想的东西提出来(掰开一般出来),一半就是另一半

数组指针和指针

int main()
{
int* p = NULL;
int arr[10] = { 0 };
return 0;
}

A.p=arr

这里的arr是一个数组首元素的地址,类型是int*所以p可以指向

B.int(*ptr)[10]=&arr

&arr是整个数组的地址,指向整个数组的地址的指针是必须是一个数组指针,所以符合

C.p=&arr[0]

同A

D.p=&arr

这里的p只是一个int*类型的指针,不是数组指针所以错误