c语言一维数组如何冒泡排序?
冒泡排序是一种常见的排序方法,反复访问要排序的元素,依次比较相邻的两个元素,如果前面大于后面就交换。用C语言实现冒泡排序时,需要使用两个循环。对于n个元素的数组A,外循环I的取值范围为0到n-1,内循环J的取值范围为0到n-1-i,若A[j]GTA[j1],则两个元素互换,直到循环结束,此时C语言中一维数组的冒泡排序完成。希望以上回答能帮到你。
c语言可以泛型编程吗?如何实现?
泛型编程是一种非常常见的编程方法。主要目的是实现静态绑定,使函数可以接受不同类型的参数,并在编译时确定正确的类型。
许多语言都支持泛型编程。例如,在C中,可以使用函数模板和类模板来实现泛型编程。在单一继承的语言中,如Java、Objective-C或C#,也可以使用similar和NSObject类型进行编程。在具有类型推理功能的编程语言(如Swift)中,可以直接使用泛型编程。
但C语言是高级语言编程的基础语言,如何用C语言实现泛型编程确实是个问题。首先,C语言不支持函数重载和模板类型,实现起来真的很难。
0x01通用指针简介(void*)
Void*是C语言中的一种类型。众所周知,在大多数编程语言中,void类型表示所谓的空类型,比如一个函数返回一个空类型void,这是非常常见的用法。
注意:void的返回值并不意味着没有返回值,而是意味着返回一个空类型,这也是为什么你仍然可以在这些函数中使用return语句的原因。只有某些语言中的构造函数和析构函数没有返回值。在这些函数中,不允许使用return语句。它们是显著不同的。Objective-C是一种独特的语言,它的类初始化方法是一种普通的方法,返回值是instancetype(当前类的指针类型)。
Void*可能有点不为人知。void*可以表示C语言中任何类型的指针。说到底,对于一个存储单元的地址来说,它存储的所谓数据类型只是每次取的字节数不一样,这些存储单元的地址本身并没有什么不同。下面会更好的体现这句话的意思。
void*的大小永远是一个字,就像普通的指针一样。具体大小因机器字长而异,例如32位机器为4字节,64位机器为8字节。
我还没有t在16位8086机上验证了指针的大小,因为8086的地址是20位。有兴趣的可以回去试试。个人认为指针大小还是16位,因为20位是物理地址,物理地址是从段地址和偏移地址计算出来的。汇编后,C语言中的指针可能只是变成了相对于段地址的偏移地址。毕竟对于8086来说,数据永远在DS段,而代码永远在CS段。(斜体表示未经核实的陈述)
在C语言中,其他常用类型的指针可以自动转换为void*type,而void*type只能强制转换为其他常用类型的指针,否则会出现警告或错误。
关于所谓的void*指向数组有一个特别大的坑,这里直接用代码解释。
voidSwap(void*array,intx,inty,intmallocsize){
void*tempmalloc(mallocsize)
memcpy(temp,数组mallocsize*x,mallocsize)
memcpy(数组mallocsize*x,数组mallocsize*y,mallocsize)
memcpy(数组mallocsize*y,temp,mallocsize)
免费(临时)
}
这是一个经典的交换函数,借助临时变量temp,不过这个函数是通用的,memcpy的用法后面会介绍。需要注意的是,如果array指向一个数组,你可以t直接用amparray[x]或者arrayx来获取指向x元素的地址,因为void*类型的默认指针偏移量是1,和char*一样,对于大多数类型都会造成错误。因此,在使用泛型类型时,我们必须知道它的原始长度。我们需要一个名为mallocsize的int类型参数来告诉我们这个值,并在计算指针偏移量时乘以它。这相当于C编程中的模板类型定义或者Java中的泛型参数。
同时要注意void*类型的指针,它可以不要在任何时候被取消参考(或者老师过去叫什么"获取内容"在课堂上?),原因很明显:void类型的变量是不合法的。因此,如果要解引用,必须先将其转换成普通指针。当在数组中使用时,还应该注意解引用操作符优先于加法操作符,所以应该加上括号,如下所示:
inta*(数组mallocsize*x)
这段代码完美体现了C语言编程的丑陋。
0x02sizeof运算符简介
Sizeof运算符相信学过C语言的朋友会比较熟悉,但是siZeof是一个运营商,很多人都不知道。返回的类型是size_t类型。sizeof运算符返回类型占用的空间量。这里唯一的要点是,如果你找到一个指针类型或数组名的大小(事实上,数组名是一个指针常量),返回的结果总是一个单词(见上文)。求一个结构类型的sizeof不是简单的结构中各种类型的sizeof之和,而是涉及到内存对齐的问题。我不这里不想介绍了。详情请访问:如何理解struct的内存对齐?-智虎。
0x03memcpy功能简介
Memcpy是一个经常和void*一起使用的函数,它的函数原型是:
void*memcpy(void*,constvoid*,size_t)
头文件属于string.h,可以看到,这个函数本身是以void*type作为参数和返回值的,其实很好理解。这是一个赋值和复制记忆的过程。将第二个参数指向的内存复制到第一个参数,复制的字节数由第三个参数指定。当然,第三个参数通常是通过sizeof运算符获得的,所以我赢了这里就不举例了。我还没有我没有研究过返回值,也没有研究过。;我没用过。如果有知道的朋友可以评论一下。
用0x04C语言实现泛型编程
话虽如此,我们还没有t还没有提到泛型编程。但是,如上所述,一般的思路是使用void*type作为泛型指针,然后使用类似于mallocsize的参数来指定占用的内存大小。占用的内存大小是通过sizeof运算符获得的。如果需要赋值,可以使用memcpy函数来完成。下面是一个直接的例子,这是一个通用的快速排序来说明这些问题:
#ifndefCompare_h
#定义比较_h
#包含ltstdio.hgt
#包含JCB.h
intIsGreater(void*x,void*y)
intIsGreaterOrEqual(void*x,void*y)
intIsSmaller(void*x,void*y)
intIsSmallerOrEqual(void*x,void*y)
#endif
//
//Compare.c
//作业调度程序
//
//鲁创作于2017/11/16。
//版权?2017鲁饶威。全部版权所有。
//
#包含比较.h
intIsGreater(void*x,void*y){
return*(int*)xgt*(int*)y
}
intIsGreaterOrEqual(void*x,void*y){
return*(int*)xgt*(int*)y
}
intIsSmaller(void*x,void*y){
return*(int*)xlt*(int*)y
}
intIsSmallerOrEqual(void*x,void*y){
return*(int*)xlt*(int*)y
}
//
//QuickSort.h
//作业调度程序
//
//鲁创作于2017/11/16。
//版权?2017鲁饶威。保留所有权利。
//
#ifndef快速排序_h
#定义快速排序_h
#包含ltstdio.hgt
#包含ltstdlib.hgt
#包含ltstring.hgt
#包含比较.h
voidQuickSort(void*array,intleft,intright,intmallocsize)
#endif
//
//QuickSort.c
//作业调度程序
//
//鲁创作于2017/11/16。
//版权?2017鲁饶威。保留所有权利。
//
#包含快速排序.h
voidSwap(void*array,intx,inty,intmallocsize){
void*tempmalloc(mallocsize)
memcpy(temp,数组mallocsize*x,mallocsize)
memcpy(数组mallocsize*x,数组mallocsize*y,mallocsize)
memcpy(数组mallocsize*y,temp,mallocsize)
免费(临时)
}
intQuickSortSelectCenter(intl,intr){
返回(左侧)/2
}
intquicksortpartition(void*array,intl,intr,intmallocsize){
intleftl
int右r
void*tempmalloc(mallocsize)
memcpy(temp,数组mallocsize*right,mallocsize)
while(左左右){
while(IsSmallerOrEqual(arraymallocsize*left,temp)ampampleftltright){
左边的
}
if(左lt右){
memcpy(数组mallocsize*right,数组mallocsize*left,mallocsize)
正确
}
while(IsGreaterOrEqual(arraymallocsize*right,temp)ampampleftltright){
正确
}
if(左lt右){
memcpy(数组mallocsize*left,数组mallocsize*right,mallocsize)
左边的
}
}
memcpy(数组mallocsize*left,temp,mallocsize)
向左返回
}
voidQuickSort(void*array,intleft,intright,intmallocsize){
if(leftgtright){
返回
}
中间中心快速排序选择中心(左,右)
交换(数组、中心、右侧、mallocsize)
centerQuickSortPartition(数组,左,右,mallocsize)
快速排序(数组,左,中间-1,移动平均llocsize)
快速排序(数组,中心1,右侧,mallocsize)
}
这里有个悬念,明明可以直接比较,何必用很多函数来完成,也就是关于Compare.h使用的问题,答案会在下面揭晓。
0x05泛型的协议问题
刚才那个问题涉及到一个通用的协议问题,我借用了Objective-C的一个概念在这里详细阐述。就像那个问题一样,既然我的快速排序是泛型的,那我怎么保证传入的实际泛型参数一定是可比较的呢?比如很明显int,float,double是可以比较的,我们也理解char使用ASCII编码方案的比较,字符串类型甚至可以比较。但是如何比较其他语言中的对象呢?这是一个问题。在C中,我们可以重载运算符,所以我们仍然可以使用比较运算符,并使用运算符来重载函数。但是Java和Objective-C呢?而如果传入的泛型参数没有实现对应的运算符重载函数呢?这时,有必要引入一个协议的概念。简单地说,如果一个类型想要成为一个排序泛型函数的泛型参数,你必须实现一个可比较的协议。这个协议在Swift语言中叫做Comparable,这样在编译的时候,编译器就会知道这个泛型参数是可以比较的,从而完成我们的操作,否则就会出错。这是泛型中的协议问题。
0x06摘要
C语言的泛型编程以void*为泛型类型,本质上是一个泛型指针。
C语言中的泛型编程需要知道泛型类型变量的内存大小,这可以通过sizeof获得并传递给泛型函数。
在C语言的泛型编程中,要注意数组的偏移量。void*的默认偏移量是1,对于大多数类型来说是错误的,需要自己编程转换。
Memcpy函数用于在C语言的泛型编程中复制和赋值泛型变量。
在C语言的泛型编程中,我们也需要注意协议问题,但是在C中,我们只能自己编写函数来定义,可以使用其他语言现成的接口或协议。