define _CRT_SECURE_NO_WARNINGS
include <stdio.h>
//
////冒泡排序 该方法只能进行整数的排序
//void BubbleSort(int arr[], int sz)
//{
// int i = 0;
// int j = 0;
// for (i = 0; i < sz - 1; i++)
// {
// for (j = 0; j < sz - 1 - i; j++)
// {
// if (arr[j] > arr[j + 1])
// {
// int tmp = arr[j];
// arr[j] = arr[j + 1];
// arr[j + 1] = tmp;
// }
// }
// }
//}
//
//打印
void print(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
//
//int main()
//{
//
// int arr[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
// int sz = sizeof(arr) / sizeof(arr[0]);
// BubbleSort(arr, sz);
// print(arr, sz);
// return 0;
//}
//使用qsrot函数进行排序
include <stdlib.h>
include <string.h>
//qsort函数
//void qsort(void* base, //base中存放的是待排序数据中第一个对象的地址
// size_t num, //排序数据元素的个数
// size_t size,//排序数据中一个元素的大小,单位是字节
// int (cmp)(const void e1, const void* e2)//是用来比较待排序数据中的2个元素的函数
// );
int cmp_int(const void* e1, const void* e2)
{
//降序排序
return (int)e2 - (int)e1; //把e1和e2void类型的转换为int类型这样就可以用于比较整形类型的数据
}
//用qsort函数对整形数组排序
void test1()
{
int arr[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_int);
}
//用qsort函数对结构体进行排序
//结构体的定义
struct stu
{
char name[20];
int age;
};
//以名字的方式排序
int sort_by_name(const void* e1, const void* e2)
{
return strcmp(((struct stu)e1)->name, ((struct stu)e2)->name);
}
//以年龄的方式进行排序
int sort_by_age(const void* e1, const void* e2)
{
return ((struct stu)e1)->age - ((struct stu)e2)->age;
}
void test2()
{
struct stu s[3] = { {"zhangsan", 20}, {"lisi", 21},{"wangwu", 22}};
int sz = sizeof(s) / sizeof(s[0]);
//qsort(s, sz, sizeof(s[0]), sort_by_name);
}
void test3()
{
struct stu s[3] = { {"zhangsan", 20}, {"lisi", 21},{"wangwu", 22} };
int sz = sizeof(s) / sizeof(s[0]);
//qsort(s, sz, sizeof(s[0]), sort_by_name);
qsort(s, sz, sizeof(s[0]), sort_by_age);
}
//通过冒泡排序的思想来模拟实现qsort函数
void Swap1(char* buf1, charbuf2, int width) //buf1和buf2是char类型的指针
{
int i = 0;
for (i = 0; i < width; i++)
{
int tmp = buf1; //该交换函数的思想是传入两个char类型的指针,指针从首地址开始
*buf1 = *buf2; //每次交换一个字节的内容然后移动一个字节直到交换完整个字节的内容
*buf2 = tmp;
buf1++;
buf2++;
}
}
void BubbleSort(int base, int num, int width, int (cmp)(const void e1, const void* e2))
{
int i = 0;
int j = 0;
for (i = 0; i <= num; i++)
{
for (j = 0; j <= num - 1 - i; j++)
{
if (cmp((char)base + j * width, (char)base + (j+1) * width) > 0)
{
Swap1((char)base + j * width, (char)base + (j+1) * width, width);
}
}
}
}
//对整形数组的排序
void test4()
{
int arr[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int sz = sizeof(arr) / sizeof(arr[0]);
BubbleSort(arr, sz, sizeof(arr[0]), cmp_int);
print(arr, sz);
}
int main()
{
//test1();
/test2();/
/test3();/
test4();
return 0;
}
该代码是使用冒泡排序的思想来实现qsort函数
//void qsort(void* base, //base中存放的是待排序数据中第一个对象的地址
// size_t num, //排序数据元素的个数
// size_t size,//排序数据中一个元素的大小,单位是字节
// int (cmp)(const void e1, const void* e2)//是用来比较待排序数据中的2个元素的函数指针,
形参类型是void*是因为需要根据要求来写出比较函数,这样就可以实现对任何类型数据的比较。
// );
现在我对这段代码的理解仅停留在对代码的实现,冒泡排序的思想已经理解的差不多了,对函数指针的理解还不够透
笔试题详解
数组名的意义:
- sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
- &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
- 除此之外所有的数组名都表示首元素的地址。
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));
sizeof(数组名)的时候计算的是整个数组的大小所以这里的输出是16
printf("%d\n",sizeof(a+0));
这里的a(即数组名)没有单独放在sizeof里a后面还加了一个0所以a表示的是首元素的地址首元素地址+0还是首元素的地址,sizeof()计算的又是所占空间的大小,
所以这里的输出结果是4/8
printf("%d\n",sizeof(a));
此处的a表示的是数组首元素的地址对首元素地址的解引用输出结果是4
printf("%d\n",sizeof(a+1));
这里的a没有单独放在sizeof里面使用a表示的是数组首元素的地址a+1表示的就是数组第二个元素的地址,所以这里输出4
printf("%d\n",sizeof(a[1]));
a[1]表示的是数组的第二个元素,输出结果为4
printf("%d\n",sizeof(&a));
&a取的是数组的地址,是地址所以输出为4/8
printf("%d\n",sizeof(&a));
&a取的是数组的地址然后对数组解引用所以输出结果为16
printf("%d\n",sizeof(&a+1));
&a表示取数组的地址,数组的地址+1跳过数组a,&a+1指向下一个数组,但其仍是地址,所以输出4/8
printf("%d\n",sizeof(&a[0]));
&a[0]取出数组首元素的地址,所以输出4/8
printf("%d\n",sizeof(&a[0]+1));
&a[0]+1取出第二个元素的地址,所以输出4/8
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));
sizeof(数组名),输出6
printf("%d\n", sizeof(arr+0));
arr+0表示数组首元素的地址,是地址就输出4/8
printf("%d\n", sizeof(*arr));
*arr对数组首元素地址解引用,sizeof计算所占空间大小,arr的元素是char类型,所以输出1
printf("%d\n", sizeof(arr[1]));
a[1]表示的是数组的第二个元素,输出结果为1
printf("%d\n", sizeof(&arr));
&arr取的是数组的地址,是地址所以输出为4/8
printf("%d\n", sizeof(&arr+1));
&a表示取数组的地址,数组的地址+1跳过数组a,&a+1指向下一个数组,但其仍是地址,所以输出4/8
printf("%d\n", sizeof(&arr[0]+1));
&a[0]+1取出第二个元素的地址,是地址所以输出4/8
printf("%d\n", strlen(arr));
char arr[] = {'a','b','c','d','e','f'};该数组没有定义\0所以向strlen函数传入数组名时会一直往后找直至找到\0才停止,所以输出结果为随机值
printf("%d\n", strlen(arr+0));
arr+0表示首元素的地址,输出结果也为随机值,原因与上相同
printf("%d\n", strlen(*arr));
*arr表示对数组首元素的解引用,strlen的形参只能时指针类型,把a传入strlen时会发生错误
printf("%d\n", strlen(arr[1]));
发生错误,理由同上
printf("%d\n", strlen(&arr));
&arr表示取出数组的地址,输出结果是随机值,因为在数组中没有定义\0
printf("%d\n", strlen(&arr+1));
&arr+1表示跳过数组arr,其仍未地址输出结果是随机值-6
printf("%d\n", strlen(&arr[0]+1));
&arr[0]+1表示数组第二个元素的地址,输出结果为随机值-1
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
sizeof(数组名)的时候计算的是整个数组的大小,数组的每个元素类型又是char类型所以这里的输出是7
printf("%d\n", sizeof(arr+0));
arr+0表示数组首元素的地址,是地址就输出4/8
printf("%d\n", sizeof(*arr));
*arr对数组首元素的解引用,数组首元素是char类型,输出结果是1
printf("%d\n", sizeof(arr[1]));
a[1]表示的是数组的第二个元素,数组首元素是char类型,输出结果为1
printf("%d\n", sizeof(&arr));
&arr取的是数组的地址,是地址所以输出为4/8
printf("%d\n", sizeof(&arr+1));
&a表示取数组的地址,数组的地址+1跳过数组a,&a+1指向下一个数组,但其仍是地址,所以输出4/8
printf("%d\n", sizeof(&arr[0]+1));
&a[0]+1取出第二个元素的地址,是地址所以输出4/8
char arr[] = "abcdef";
printf("%d\n", strlen(arr));
strlen函数计算的是字符串的长度,arr表示的是整个数组的地址,所以输出结果为6
printf("%d\n", strlen(arr+0));
arr+0表示数组首元素的地址,输出结果是6
printf("%d\n", strlen(*arr));
*arr表示对数组首元素的解引用,strlen的形参只能时指针类型,把a传入strlen时会发生错误
printf("%d\n", strlen(arr[1]));
发生错误,理由同上
printf("%d\n", strlen(&arr));
&arr表示数组的地址,输出结果为6
printf("%d\n", strlen(&arr+1));
&arr表示取数组的地址,数组的地址+1跳过数组arr,输出结果为随机值
printf("%d\n", strlen(&arr[0]+1));
&arr[0]+1表示的是第二个元素的地址,输出结果为5
char* p = "abcdef";
printf("%d\n", sizeof(p));
这里的p指向的是字符串字符a的地址,所以输出结果为4/8
printf("%d\n", sizeof(p+1));
p+1指向的是字符b的地址,所以输出结果为4/8
printf("%d\n", sizeof(*p));
*p表示对字符a进行解引用,,strlen的形参只能时指针类型,把a传入strlen时会发生错误
printf("%d\n", sizeof(p[0]));
发生错误,理由同上
printf("%d\n", sizeof(&p));
p表示的是字符a的地址,&p表示取出p的地址是一个二级指针,是地址输出结果为4/8
printf("%d\n", sizeof(&p+1));
&p+1是地址,所以输出结果为4/8
printf("%d\n", sizeof(&p[0]+1));
&p[0]表示取出字符a的地址,+1就是取出字符b的地址,是地址就输出4/8
char* p = "abcdef";
printf("%d\n", strlen(p));
这里的p指向的是字符串字符a的地址,输出结果是6
printf("%d\n", strlen(p+1));
p+1指向的是字符串字符b的地址,输出结果是5
printf("%d\n", strlen(p));
p表示对字符a进行解引用,,strlen的形参只能时指针类型,把a传入strlen时会发生错误
printf("%d\n", strlen(p[0]));
发生错误,理由同上
printf("%d\n", strlen(&p));
/&p指向p,p指向字符a的地址,所以输出结果为6/,输出结果应为随机值
printf("%d\n", strlen(&p+1));
/&p指向p,p指向字符a的地址,+1指向的是字符b的地址,所以输出结果为5/,输出结果应为随机值
printf("%d\n", strlen(&p[0]+1));
&p[0]表示取出字符a的地址,+1就是取出字符b的地址,输出结果为5
//二维数组
int a[3][4] = {0};
printf("%d\n",sizeof(a));
a表示的是整个二维数组的地址,所以输出结果为344=48
printf("%d\n",sizeof(a[0][0]));
arr[0][0]表示的是下标为0 0的元素,所以输出结果为4
printf("%d\n",sizeof(a[0]));
a[0]表示的是第一行的数组名,所以输出结果为16
printf("%d\n",sizeof(a[0]+1));
a[0]没有单独放在sizeof里所以在这里a[0]代表的是第一行第一个元素的地址,+1表示第一行第二个元素的地址,所以输出结果为4/8
printf("%d\n",sizeof((a[0]+1)));
a[0]+1表示第一行第二个元素的地址,对它进行解引用,输出结果为4
printf("%d\n",sizeof(a+1));//第一次做不出来
a虽然是二维数组的地址,但是并没有单独放在sizeof内部,也没有取地址,a表示首元素的地址,二维数组首元素的地址是第一行,a就是的地址,a+1表示的就是第二行的地址
是地址输出结果就是4/8
printf("%d\n",sizeof((a+1)));
a+1表示的就是第二行的地址,对第二行进行解引用输出结果是16,(a+1)-->a[1]
printf("%d\n",sizeof(&a[0]+1));
a[0]是第一行的数组名,&a[0]取出的是第一行的地址,+1取出的是第二行的地址
printf("%d\n",sizeof((&a[0]+1)));
(&a[0]+1))对第二行进行解引用,输出结果为16
printf("%d\n",sizeof(a));
a没有单独放在sizeof里a就表示二维数组首元素的地址即第一行的地址,对其解引用输出结果为16
printf("%d\n",sizeof(a[3]));
a[3]-->*(a+3),输出结果为16
课堂杂记:
strlen函数是求字符串长度的,关注的是字符串中的\0,计算的是\0之前的字符个数;
strlen是库函数,只针对字符串;
sizeof只关注占用内存空间的大小,不在乎内存中存放的是什么;
sizeof是操作符;