本文已参与「新人创作礼」活动,一起开启掘金创作之路
一维数组
初识数组
#include <stdio.h>
int main(){
int x;
double sum =0;
int cnt = 0;
int number[100];//定义数组
scanf("%d",&x);
while(x!=-1){
number[cnt]=x;//对数组中的元素进行赋值
sum+=x;
cnt ++;
scanf("%d",&x);
}
if(cnt>0){
int i;
double average =sum/cnt;
//遍历数组
for(i=0;i<cnt;i++){
if (number[i]>average){
printf("%d\t",number[i]);//使用数组中的元素
}
}
}
}
定义数组
<类型>变量类型[元素数量]
例如:int grades[100];
int weight[20];
- 元素的数量必须是整数型
C99之前:元素数量必须是编译时刻确定的字面量
那么问题来了怎么理解数组呢?
- 是一种容器(放很多东西的地方),特点是
- 其中所有元素具有相同的数据类型
- 一旦创建,不能改变大小
- 数组中的元素在内存中是连续一次排列的
- 数组中的第一个元素是从0开始的
int a[10]
| a[0] | a[1] | a[2] | a[3] | a[4] | a[5] | a[6] | a[7] | a[8] | a[9] |
|---|
- 每一个单元变量都是int类型
- 可以出现在赋值的左边或右边
- a[2]=a[1]+6
- 在赋值的左边叫左值
数组的单元
- 数组的每一个单元就是数组类型的一个变量
- 使用数组时放在[]中的数字叫做下标或索引,下标从0开始计数
有效的下标范围
- 编译器和运行环境都不会检查数组下标是否越界,无论是对数组单元做读还是写
- 一旦程序运行,越界的数组访问可能造成问题,导致程序崩溃(segmentation fault)
- 保证使用有效下标值:[0,(数组的大小-1)]
数组越界:用户输入到数组的个数数组定义的个数 后果:程序会在此处崩溃
解决方案:1.在用户读数时进行计数,如果读入的数超出了数组,那么就不再读入
2.让用户先输入来决定数组的大小,然后再来记录输入
恶趣味:可以创建一个长度为0的数组,即 int a[0],但好像并没有什么卵用😋
统计个数
#include <stdio.h>
int main(void)
{
const int number =10 //数组的大小
int x;
int count[number]; //定义数组
int i;
for(i=0;i<number;i++){
count[i]=0; // 初始化数组
}
scanf("%d",&x);
while(x!=1){
if(x>=0 && x<=9){
count[x] ++; // 数组参与运算
}
scanf("%d",&x);
}
for(i=0;i<number;i++){
print("%d:%d",i,count[i]) //遍历数组输出
}
return 0;
}
数组运算
- 在一组给定的数据中,如何找出某个数据是否存在?
数组的集成初始化
int a [] = {1,2,3,4,5,6,7,8,9,0};
imt a [4] ={[0] =2, [2] = 3,6,5,7};
- 用[n]在初始化数据中给出定位
- 没有定位的数据接在前面的位置后面,即6会被放在第四位([3])
- 其他位置的值补零
- 也可以不给出数组大小,让编译器算
- 特别适合初始数据稀疏的数组
数组的大小
-
sizeof给出整个数组所占据的内容的大小,单位是字节 -
sizeof(a)/sizeof(a[0])用来表示数组有多少个单元 -
sizeof(a[0])给出数组中单个元素的大小,于是相除就得到了数组单元的个数 -
这样的代码,一旦修改数组中初始的数据,不需要修改遍历的代码
数组的赋值
数组不能直接赋值给另一个变量
- 数组变量本身不能被赋值
- 要把一个数组的所有元素交给另一个数组,必须采用遍历
for(i=0 ;i<length; i++){
b[i]=a[i];
}
-
通常都使用for循环,让循环变量i从0到小于数组的长度,这样循环体内最大的i正好是数组最大的有效下标
-
常见错误
循环结束条件是<=数组长度,或;
离开循环后,继续用i的值来做数组元素的下标!
- 数组作为函数的参数是:
- 不能在[]中给出数组大小
- 不能再利用
sizeof来计算数组的元素个数
二维数组
二维数组
int a[3][5];
通常理解为a是一个3行5列的矩阵
| a [0] [0] | a [0] [1] | a [0] [4] | a [0] [2] | a [0] [3] |
|---|---|---|---|---|
| a [1] [0] | a [1] [1] | a [1] [4] | a [1] [2] | a [1] [3] |
| a [2] [0] | a [2] [1] | a [2] [4] | a [2] [2] | a [2] [3] |
二位数组的遍历
for (i=0;i<3;i++){
for(j=0;j<5;j++){
a[i][j]=i*j;
}
}
-
a[i] [j]是一个int
-
表示第i行第j列
a[i,j]是什么?———————— =a[j]
二维数组的初始化
int a[][5]={
{0,1,2,3,4,},
{2,3,4,5,6},
};
- 列数是必须给出的,行数可以由编译器来数
- 每一行{},逗号隔开
- 最后的逗号可以存在(可以装逼)
- 如果省略,表示补零
- 也可以用定位(
c99)
最外层大括号可以不要
c语言的函数
什么是函数
是一个能接收零个或多个参数并返回零个或一个值的代码块
可以把这里的函数类比为数学中的函数
定义函数
void sum(int a,int b) //函数头
{
int 1; //函数体
int sum=0;
for(i=a;i<=b;i++){
sum+=i;
}
printf("%d到%d的和是%d\n",a,b,sum);//函数体
}
void:返回类型 ,表示空类型的函数,不需要返回,其他所有函数类型都要return来返回
sum:函数名,在引用该函数时需要使用
函数体:函数的主题部分,就是决定函数究竟是干什么用的
(int a,int b):参数表(数据类型+名字)【可以不用写名字,有数据类型即可】
函数的调用
函数名(参数值);
()起到了表示参数调用的重要作用,即使没有参数也要有()
如果有参数,给出正确的数量和顺序,这些值会按照正确顺序依次用来初始化函数中的参数
函数的返回值
//素数求和
int isprime(int i)
{
int ret = 1;
int k;
for(k=2;k<i-1;k++){
if(i%k==0){
ret=0;
break;
}
}
return ret;
}
int max(int a,int b){ | int max(int a,int b){
int ret; | if(a>b){
if(a>b){ | return a;
ret=a; | }else{
}else{ | return b;
ret=b; | }
} | }
return ret; |
}
上述两行代码,你觉得那个更好???
return
- 停止函数执行,并送回一个值
- return;
- return 表达式;
- 一个函数语句可以出现多个return语句
注意,一个函数中尽量不要有多个return,即尽量保持单一出口。这样做是为了方便修改代码
int a,b,c
a=5;
b=6;
c= max(10,12);
c= max(a,b);
c= max(c,23);
c= max(max(c,a),5);
printf("%d",max(a,b));
max(12,13)
- 可以赋值给变量
- 可以再传递给函数
- 可以丢弃
如果函数有返回值,必须带return
函数的先后关系
1.函数先后关系
与脚本语言相同,c的编译器是自上而下分析代码的。即函数的先后也是自上而下的
2.函数声明(函数原型)
#include <stdio.h>
void sum(int a,int b)
{
int 1;
int sum=0;
for(i=a;i<=b;i++){
sum+=i;
}
printf("%d到%d的和是%d\n",a,b,sum);
}
int main()
{
sum(1,10);
sum(20,30);
return 0;
}
#include <stdio.h>
void sum(int a,int b) //函数声明
int main()
{
sum(1,10);
sum(20,30);
return 0;
}
void sum(int a,int b) //定义
{
int 1;
int sum=0;
for(i=a;i<=b;i++){
sum+=i;
}
printf("%d到%d的和是%d\n",a,b,sum);
}
比较上述两行代码,你发现了什么不同吗?
上面的代码与下面的代码相比下面的代码多了一行 void sum(int a,int b)
这里多了一行函数声明,由于c的函数读取是自上而下的,所以如果没有函数声明,我们的编译器会识别不了sum,从而导致程序运行错误!!!
参数的传递
参数
-
如果函数有参数,调用参数时必须传递给它数量、类型正确值
-
可以传递给函数的值是表达式的结果
- 字面量
- 变量
- 函数的返回值
- 计算的结果
int a,b,c a=5; b=6; c= max(10,12); c= max(a,b); c= max(c,23); c= max(max(23,45),a); c= max(23+45,b);
参数传递数据类型的不一致
#include <stdio.h>
void cheer(int i)
{
printf("cheer %d",i)
}
int main()
{
cheer(2.4);
return 0;
}
上述的代码中函数定义为整数int类型,而主函数中cheer的是浮点数double类型。所以猜猜会发生什么?
没错,答案会输出2
这里答案会按照函数的定义来输出,c的编译器会在内部给你做一个转换。这是c的最大漏洞
我们传的参数是什么
void swap(int a,int b);
int main()
{
int a=5;
int b=6;
swap(a,b);
printf("a=%d b=%d",a,b);
return 0;
}
void swap(int a,int b){
int t=a;
a=b;
b=t;
}
- 这样的代码能交换a和b吗?
c语言在调用函数的时候,永远只能传值给函数
- 每个函数有自己的变量空间,参数也位于这个独立空间,和其他函数没关系
形式参数和实际参数
对于函数参数表中的参数,叫做形式参数,调用函数给的值叫实际参数
现在,我们不区分实参和形参,我们通常把函数表中的叫做参数,调用函数并参与运算的叫做值
本地变量
定义在函数内部的变量
- 函数每次运行,产生一个独立的变量空间,在这个空间中的变量就是函数这次运行所独有的,叫做本地变量
- 生存期:什么这个变量时候出现到什么时候消亡
- 作用域:在什么范围可以访问这个变量(这个变量可以起作用)
- 对于本地变量,以上的生存期和作用域是统一的:大括号内
本地变量的规则
- 本地变量定义在块内,它可以定义在函数块内,也可以定义在语句块内
- 甚至可以随便拉一对大括号定义变量
void swap(int a,int b);
int main()
{
int a=5;
int b=6;
{
int i=0;
printf("%d",i); //可以随便用一对大括号定义变量
}
swap(a,b);
printf("a=%d b=%d",a,b);
return 0;
}
void swap(int a,int b){
int t=a;
a=b;
b=t;
}
void swap(int a,int b);
int main()
{
int a=5;
int b=6;
{
printf("%d",a); //块的嵌套,最外层大括号是主层
}
swap(a,b);
printf("a=%d b=%d",a,b);
return 0;
}
void swap(int a,int b){
int t=a;
a=b;
b=t;
}
- 程序运行进入块之前,其变量就不存在了,离开块,其中变量就消失
- 块外面定义的变量在里面仍然有效,而在里面定义的在外面无效,即就整体而言大块的优先级高于小块
- 块里面定义和外面的变量同名,在块内运行时覆盖外面的
void swap(int a,int b);
int main()
{
int a=5;
int b=6;
{
int a=0;
printf("%d",a);
}
swap(a,b);
printf("a=%d b=%d",a,b);
return 0;
}
void swap(int a,int b){
int t=a;
a=b;
b=t;
}
其他细节
没有参数时
- void f(void);
- void f();
- 在传统C中,它表示f函数的参数未知,并不表示没有参数
void swap();
int main()
{
int a=5;
int b=6;
swap(a,b);
printf("a=%d b=%d",a,b);
return 0;
}
void swap(double a,double b){
int t=a;
a=b;
b=t;
}
这样写时告诉c语言swap是个函数,但不知道是什么类型,所以c会默认给你补一个整数类型,接着往下运行时会发现swap时浮点是类型,和所猜的不一样,最后输出就会是一个很奇怪的数
逗号运算符号
调用函数时的逗号和逗号运算符怎么区别
- 调用函数时的括号里逗号就是标点符号,不是运算符
- f(a,b)
- 如果是与运算符
- f((a,b))
注意
-
c语言中函数里面不能嵌套函数
-
int i,j,sum(int a,int b); 意思是定义i,j和函数sum
int main()
- int main()是一个函数,叫主函数
- return的0
Windows:if error level 1....(P处理文件/bat文件)Unix Bash:echo $?Csh:echo $status
int main(void)也可以
一个程序返回0表示运行正常结束了,否则返回任何一个非0值都是出现了错误