硬核干货!数组、还有函数(5)

10 篇文章 0 订阅
10 篇文章 0 订阅

数组和函数

所谓数组,是有序的元素序列,C语言中的数组其实就是一组同类型的变量。
而函数是具有某些特殊功能的代码段,必须先声明才能够调用函数。

一维数组

一:数组声明

数据类型  数组名[数组长度];
数据类型  数组名[] = {数据元素,...};   //用数组元素来确定数组长度
     //不显示指定数组长度的形式,必须通过 = {} 这样的方式来初始化
数据类型  数组名[变量];  //变量值依然可以改变,但是一旦数据定义之后,数组长度就不会发生变化

二:数组初识化:

 int arr[3] = {1,2,3};//----赋值
 int brr[3] = {1,2,3,4};//警告  但不会编译报错   多余的舍弃
 int crr[3] = {1,2};// 少的部分补0
 int drr[3] = {0};//全部初始化为0
 int err[3] = {};//全部初始化为0
 int frr[3] = {[1]=1,[0]=2};//指定位置元素初始化  其它都为0
   //适合于只有少数位置有值的时候的初始化
 int grr[] = {1,2,3,...};//由元素个数来决定数组长度
 int hrr[] = {[0]=1,[2]=3};//数组长度=最大下标+1

错误的初始化:

int irr[] = {};//语法允许  但不会这样用
int arr[3] = 0;//错误
int brr[];     //错误

长度为变量时的初始化为0:

int a[n];
int i = 0;
for(;i<n;i++){
	a[i] = 0;
}

注意:

  1. 数组定义时一般会进行初始化,否则数组中的元素是垃圾值
  2. 数组一旦定义之后,数组名不能作为左值

三:访问数组

访问数组元素时,同一使用下标。

数组名 [ 下标 ]

下标取值范围: [ 0 , 数组长度-1 ]

数组长度 = sizeof(数组名)/ sizeof(数组名[0])
( 数组长度=sizeof(数组名) / 单个元素内存字节大小)

下标取值不能超过范围(数组不能越界):
数组越界不会说100%出现问题,但是数组越界一定要避免
(1)核心已转储(段错误)
(2)有的时候不一定会产生核心段错误,也有可能是逻辑错误

二维数组

一:二维数组定义

  数据类型  数组名[二维长度][一维长度];
   //二维数组二维长度可以有元素的个数来决定,但是一维长度不能省略
  数据类型  数组名[][一维长度];
  数据类型  数组名[变量][变量];

二:二维数组的初始化

  int arr[3][4] = {{1,2,3,4},{2,3,4,5},{7,8,9,9}};
  int brr[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
  int crr[3][4] = {1,2,3,4,5,6};
  int drr[3][4] = {0};
  int err[3][4] = {};
  int frr[3][4] = {[0]=0,[1]={1,2,3,4},[2][3]=7};
  int grr[][4] = {1,2,3,4,5};

当长度都为变量时的初始化为0:

int a[n][m];
int i=0,j=0;
for(;i<n;i++){	
	for(;j<m;j++){
		a[i][j] = 0;
	}
}

三:二维数组的访问

访问二维数组元素时,也是使用下标访问。

行和列,都是从0开始,小于维度的长度

例:
int arr[3][4]; 有3个长度为4的一维数组

二维数组的遍历:一行一行遍历、一列一列遍历

函数

一:c语言提供了一些必要的功能函数,同时也能自定义函数

一些基本的库函数:

printf() scanf() exit() time() rand() abs sqrt()

main函数(主函数):

(1)是c语言函数的入口,一个进程运行之后 ,指定调用main函数。
(2)如果没有main函数,gcc编译时会报没有main函数的错误。
(3)一个C语言程序中有且只能有一个main函数
(4)main函数可以调用其他函数,也可以被其他函数调用

自定义函数:

定义位置:在main函数外面(一般来说在main函数上面)

二:函数的语法规则(函数的要素)

返回值类型  函数名(形参列表){
 函数体;
}

返回值类型:

(1)函数可以返回一个结果,在定义函数时必须指定该结果的类型
函数也可以没有返回值,那么可以用void(函数不需要结果,可能只是一个过程)
(2) 函数的返回值通过return语句返回
return值 :值的类型要和函数返回值类型一致
(3) return语句还有一个作用,即从函数返回 退出函数 结束函数调用
(4)C语言中函数的返回值类型默认为int,如果返回值类型为int ,可以不用写

main函数的返回值的作用:

(1)用于父进程判断进程是否正确执行
(2)在命令行用 echo $? 可以获得上一个程序(进程)的返回结果

函数名:

标识符

形参列表:

(1)参数使得函数的作用更加灵活
(2)形参列表的格式: 参数类型 形参名,参数类型 形参名,...
(3)形参列表可以为空,但是即使多个形参变量的类型一致 参数的类型也不能省略
(4)形参变量是用来接收调用函数时所传递的值 (在调用函数时传递的值称为实参)

函数体:

函数的功能实现代码,一定要在 大括号{} 里面

void:

(1)作用函数的返回值类型 表示该函数没有返回值
如果在函数中需要提前结束时,可以直接用return
(2)形参列表为()样子的时侯,表示该函数并不关心参数,在调用该函数时,可以传递任意类型任意多的实参
(3)形参列表为(void)样子的时候,表示该函数不接收任何类型的参数

return:

(1)返回一个结果给函数调用者
(2)结束本函数

三:函数的调用
函数定义之后,可以调用,所谓调用函数可以理解成程序跳到函数里去执行

函数名  (实参列表);   //函数调用时即使没有实参,小括号() 也不能少

注意:

  1. 函数调用需要开辟内存空间用于存储数据
  2. 函数调用需要时间的消耗
  3. 频繁地调用函数其实是有损性能的

四:函数的隐式声明:

(1) 当gcc编译器编译到一个在此之前没有定义和声明的函数,并不会直接中断编译,而是会隐式声明一个同名的函数
(2) 隐式声明的函数默认返回值类型为 int
(3)当编译到最后的链接阶段时,如果确实没有这个函数,则编译会报错
(4) 如果有同名的函数且返回值类型不一致的函数,则编译警告

gcc编译有四个步骤:预处理阶段 、编译阶段、汇编阶段、链接阶段

变量名未定义是在编译阶段报错
函数没有定义是在链接阶段报错

五:递归函数
函数自己内部调用了自己

找规律
求解的问题时一个关于n的系数(参数)
这个问题的解只由一些小于n的系数的解组成

1.退出条件,(不能无限制地调用自己调用下去)
2.公式(一个复杂的问题分解成几个相对不那么复杂的问题)

注意:
递归调用次数太深会造成栈溢出(特别是斐波那契这样每一次调用会产生新的两个调用的函数)

六:快速排序:可以看作是一个递归调用的过程

思路:记录一个基准值(最左边的值)
     再记录左闭区间下标i 和右闭区间的下标j
      只要i<j 就
 	  从右边找到一个比 基准值key 要小的数,a[i] = a[j]
	  从左边找到一个比 基准值key 要大的数,a[j] = a[i]
      如果上面结束 那么 i==j
   	  arr[i] = key  这个位置存储key
  	  arr[i]左边的值会小于等于key
 	  arr[j]右边的值会大于等于key
 	  对于key而言 位置已经确定
      然后再对 左半区间 和 右半区间 重复上面的动作即可

代码示例如下:

#include <stdio.h>

void show(int arr[],int n){
 	int i = 0;
 	for(;i<n;i++){
  		printf("%d ",arr[i]); 
 	}
 	printf("\n");
}
//能对数组[left,right]区间的数据进行排序
void quick(int arr[],int left,int right){
 	if(left >=right){//最多只有一个元素 啥也不用干
		  return; 
 	}
	int key = arr[left];//基准
 	int i = left;
	int j = right;
 	while(i<j){
  		while(i<j&&arr[j]>=key){--j;}//循环结束之后arr[j]小于key
  		arr[i] = arr[j];
  		while(i<j&&arr[i]<=key){++i;}//循环结束之后arr[i]大于key
  		arr[j] = arr[i];
	 }
	 arr[i] = key;
 	 quick(arr,left,i-1);//递归调用
 	 quick(arr,i+1,right);//递归调用
}

void sort(int arr[],int n){
 	quick(arr,0,n-1); 
}

int main(){
 	int arr[10] = {56,34,27,46,88,90,20,17,68,72};
 	int n = sizeof(arr)/sizeof(arr[0]);
 	show(arr,n);
 	sort(arr,n);
 	show(arr,n);
 	return 0; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值