C语言学习记录230618

        感动到我想哭啊,今天是正经报班学习以来,头一次不是第二天发的博文,虽然今天也跟昨天一样是学了两节课,但是可能是因为我之前自学的内容比较扎实,今天的课基本全程两倍加速加跳过去看的,要说有没有收获,有倒是有,但是没之前的课那么多,但是今天自己按照快速排序的原理自己去写了一个程序,反而比较费事,这个程序我会再文章最后贴出来,写完以后发现有许多地方的参数还是可以优化,包括我本身的知识水平也还有限,大佬轻喷。

        (一)函数

                C语言中的函数,跟数学概念中的函数概念还是有所差别的,C语言中的程序跟数学的函数最大的差别在意,C语言的函数,它可以没有参数,也可以不用计算数值。C语言的函数本质上就是一个自带声明和语句的小程序。它还有一个名字叫做子程序,这个名字相对前面的解释则更加清晰明了,子程序指的就是由一个或多个语句组成的具有一定独立性的代码模块。

                ①库函数

                讨论库函数之前,其实我们可以了解到,C语言其实一开始并没有所谓的库函数,但是很多常用的功能几乎人人都要用,这个时候每个人都会按自己想法去写一个相似或者类似功能的代码,这个时候就会出现一个问题,每个人写的代码和逻辑都不太一样,但实现的功能都差不多,这时候在移植程序的时候就容易出现兼容性问题,打个比方,我们知道printf函数会返回打印的字符数量,那如果有的人按自己想法打印,他就不返回数值,而有的程序内引用该返回值去做一些操作,就会出现问题(虽然这种情况很少)。所以我们为了解决上面这些问题,就出现了库函数,库函数的出现提高了编程效率,提高了标准性,进而减少了编程错误。

                库函数的使用可以通过Cplusplus、、MSDN或者官网等途径去查看,这些地方都能查看C语言库函数内对应库的函数原型及其说明,有了这些我们就可以自行摸索其使用方法。

                使用库函数内的函数都需要在指令(头文件)内写清楚这些函数所属的库,比如scanf和printf函数都属于stdio库(标准输入/输出库),而system函数属于stdlib库,若使用了这些函数而没有在头文件内写清楚这些函数所属的库,那么在编译时会产生报错或者警告。

                这里可以说下今天学到的自己不知道的一个库函数,就是memset函数,这个函数需要输入三个参数,第一个参数是对应的内存空间首地址,第二个参数需要传入需要修改的内容,第三个参数传入需要修改的内存空间大小,这个大小时从首地址来算的。

                ②自定义函数

                库函数固然功能强大,但其针对的都是一些常用的功能,为了解决现实生活中各种复杂的情况,就需要我们根据自己的情况和需求,编写适用于各种情况的自定义函数。

                自定义函数可以不声明,但是一定要定义,定义一个函数需要写出这个函数的返回值、函数名称、需要传入的数据类型及其数量,最后需要写出这个函数所包含的声明、语句。
                其形式是:

        返回类型   函数名  (形式参数类型  形式参数名1,形式参数类型  形式参数名2,……)

        {变量声明(可以没有);语句;}

                当其他程序需要调用这个自定义函数时,那个函数必须要再这个自定义函数定义的下面,不然程序会无法识别这个函数调用的自定义函数。很多时候我们的自定义函数会写的又臭又长,那主程序就会放在非常下面,不利于阅读,所以为了解决这种问题,我们可以采用函数声明+函数定义的方式来解决,我们可以把函数声明放在调用这个函数的程序前面,这样程序就能先读到声明,从而知道我们调用的是一个函数,而把函数定义写在主程序下方,这样函数也能正常调用。(括号内的形式参数不为空的函数,它的声明,我们也称之为函数原型)。函数定义形式同上面,函数声明如下:

          返回类型   函数名  (形式参数类型  形式参数名1,形式参数类型  形式参数名2,……);

                我们可以发现其实基本跟函数定义式差不多的,就是多了个“;”号,但其实函数声明里,形式参数的参数名是可以不加的,所以可以写成这个样子:

        返回类型   函数名  (形式参数类型  ,形式参数类型  ,……);

        (二)形式参数和实际参数

                我们前面反复提到的形式参数,我们接下来会做一下简单的讨论,形式参数指的是函数定义和函数声明开头那一串里的参数,而实际参数,指的是在调用这个函数时,根据这个函数的定义和声明,对应输入的参数。简单给出一个例子:

void Print(int ,int );

int main(void)
{
    int a,b;
    while(scanf("%d%d",&a,&b)!=2)getchar();
    Print(a,b);
    return 0;
}

void Print(int num1,int num2)
{
    printf("%d %d",num1,num2);
}

                这里的a,b就是实际参数,num1和num2就是形式参数,而最上面的函数原型,可以看到形式参数类型并没有给出对应的形式参数名,实际上,声明里的形式参数名可以跟后面定义上的不一样,但注意一点,参数类型和数量必须要对得上。

void Swap(int ,int );

int main(void)
{
    int a,b;
    while(scanf("%d%d",&a,&b)!=2)getchar();
    Swap(a,b);
    printf("%d %d",a,b);
    return 0;
}

void Swap(int a,int b)
{
    int temp=0;
    temp=a;
    a=b;
    b=temp;
}

                这里再给出一个例子,我们可以发现形式参数的参数名和实际参数的参数名一样了,这段自定义函数的作用是交换两个数的值,那么最后主程序输出a和b的值时,两者的值是否会交换呢?答案是否定的,假如输入了1 2,那么最后输出的仍然会是1 2,而不是2  1。

                如果观察一下形式参数内变量a和b的地址,再观察一下主程序内的变量a和b的地址,会发现两者的地址的不一样的,这说明自定义函数内的形式参数是一个新的变量,所以结论是实际参数仅仅只是把他的数值传给形式参数,而不是实际参数本身进去,因而在自定义函数内对形式参数a和b做出的修改,不会对主程序的实际参数有任何影响。形式参数跟局部参数几乎完全一样,唯一的区别在于,形式参数是在实际参数传入的时候就初始化了,而局部参数可以从头到尾都不初始化。

                那么又产生了一个疑问,如何让自定义函数也能对主程序内的a和b产生影响呢?这里的解决方案就是传入一个指针,a和b的地址是不会变的,那我们只要传入地址,管他新建立的指针变量在哪里,只要地址是对的,那我们总能找到a和b,并对变量做出修改,修改后,上面的例子变成下面这样的形式:

void Swap(int* ,int* );

int main(void)
{
    int a,b;
    while(scanf("%d%d",&a,&b)!=2)getchar();
    Swap(&a,&b);
    printf("%d %d",a,b);
    return 0;
}

void Swap(int *a,int *b)
{
    int temp=0;
    temp=*a;
    *a=*b;
    *b=temp;
}

                 修改后,我们通过取地址运算符,将a和b的地址送入到Swap自定义函数内,然后采用间接寻址运算符,对a和b做出实际修改。

                但有时候我们未必需要对主程序内的参数进行实际修改,我们可以只需要返回一个具体的数值,比如我们求a和b的和,那我们就只需要返回a和b的和就行,并不需要对a和b进行修改。

                当传入自定义函数的参数仅仅是数值时,我们称之为传值调用,而当我们传入自定义函数的参数为地址指针时,我们称之为传址调用。

                最后说明一下,函数的调用是可以嵌套的,也就是某个函数内也可以直接调用其他的函数,这种方式也叫做嵌套调用。而在函数调用时,传入的参数数值也可以是一个函数计算的结果,这种调用我们称之为链式调用。这些概念其实意义不大,就是简单说一下,可以看出来C语言的使用是很自由的。

        (三)杂谈

                ①素数计算

                日常杂谈一下,主要还是这两天写一些作业,还有一些自己看书敲的程序收获,之前在PTA写了很多题目,对于素数的计算,我还停留在非偶数这种方式,后来写的多了,也就知道可以从2到小于等于根号对应数字,来求。今天才算知道了原理,假设要知道一个变量num是不是素数,假如num不是素数,那么他就必然有一个因数a和一个因数b,那么num=a*b。

                我们可以发现a和b的值必然有一个是小于等于根号num的,从这个原理我们就可以简化自己的计算。后来讲师还推荐了我们一本书,叫《求素数的N种境界》,听来还是挺有趣的,希望以后有机会拜读一下。

                ②快速排序、二分法查找

                二分法查找原理很简单,由于我已经写过很多次了,也就懒得说了。今天自己根据书本的原理,尝试着自己写了一下快速排序的程序,想到结合二分法查找,这也算是搞了一个排序和查找功能的程序了,意外还挺有成就感的。下面给出今天写的快速排序法程序代码:

#include<stdio.h>
 
#define N sizeof(number)/sizeof(int)

//函数原型 
void Quick_sort(int* ,int ,int );
void Mid_number(int* ,int ,int ,int );
int Split(int* ,int ,int );

//主程序 
int main(void)
{
	int number[]={12,345,4,65,76,58,678,567,23,423,67,5,78,67,8};//测试用数组,必要可成自增数组 
	int len=N;
	int i;
	
	Quick_sort(number,0,len-1);
	for(i=0;i<len;i++)
	{	
		if(i!=0)printf(" ");
		printf("%d",number[i]);
	}
	
	return 0;
}

//自定义函数一:快速排序自定义函数的控制部分 
void Quick_sort(int number[],int left,int right)
{
	int mid;
	
	if(left<right)
	{
		mid=Split(number,left,right);
		Quick_sort(number,left,mid-1);
		Quick_sort(number,mid+1,right);
	}
}

//自定义函数一:快速排序自定义函数的功能部分 
void Mid_number(int number[],int num1,int num2,int num3);
int Split(int number[],int left,int right)
{
	int temp = 0;
	int status=1;
	
	Mid_number(number,left,left+(right-left)/2,right);
	temp=number[left];
	while(left<=right)
	{
		if(status)
		{
			if(number[right]>=temp)
				right--;
			else
				{
					number[left]=number[right];
					left++;
					status=0;
				}
		}
		else
		{
			if(number[left]<=temp)
				left++;
			else
			{
				number[right]=number[left];
				right--;
				status=1;
			}
		}
		if(left==right)
		{
			number[left]=temp;
			break;
		}
	}
	
	return left;
}

//自定义函数二:把起始、末端和中间值的数值比对,并把中间值移动到数组的第一位 
void Mid_number(int number[],int num1,int num2,int num3)
{
	int value = 0;
	
	if(num1==num2&&num3==num2)return; 
	value=number[num1];
	if(number[num1]<number[num2]&&number[num1]<number[num3])
	{
		if(number[num2]<number[num3])
		{
			number[num1]=number[num2];
			number[num2]=value;
		}
		else
		{
			number[num1]=number[num3];
			number[num3]=value;
		}
	}
	else if(number[num1]>number[num2]&&number[num1]>number[num3])
	{
		if(number[num2]<number[num3])
		{
			number[num1]=number[num3];
			number[num3]=value;
		}
		else
		{
			number[num1]=number[num2];
			number[num2]=value;
		}
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值