C语言的小小进阶:函数、数组、二位数组、指针

1.函数定义

①.无返回值的函数:
	函数头[返回类型] 函数名(参数表)
	void sum(int begin,int end){函数体}

	不能使用带值的return,可以没有return。

②.有返回值的函数:
	int max(int a,int b){函数体}

一个函数中可以有多个return。
在函数中设置单一出口更好。

2.函数先后关系

C语言的编译器自上而下的顺序分析你的代码。
如果把要调用的函数放在主函数下面则会报错。

3.函数原型

函数头,以分号“;”结尾,构成了函数的原型。
其目的是告诉编译器这个函数的样子:
		名称、参数、返回类型

4.参数传递

可以传递:字面量、变量、函数的返回值、计算的结果

若是类型不匹配?
	调用函数时给的值与参数类型不匹配是C语言传统上最大的漏洞;
	编译器会自动帮你把类型转换好,但可能不是你所期望的;
	后续的语言,c++/java在这方面很严格。

C语言在调用函数时,永远只能传值给函数。

5.函数的参数和变量

5.1 本地变量
①.函数的每次运行就产生一个独立的变量空间,在则会个空间中的变量,
是函数的这次运行所独有的,称作本地变量。
②.定义在函数内部的变量就是本地变量。
③.参数也是本地变量。

生存期:什么时候这个变量开始出现,到啥时候它消亡了
作用域:在那个范围内可以访问到它(可以起作用)
对于本地变量,这个两个问题答案统一:在打括号(块)内。

本地变量的规则:
	本地变量是定义在块内的;
	程序进入这个块前其中变量不存在,离开后变量消失;
	块外面定义的变量在块内仍然存在;
	在块内的同名变量会将块外的覆盖使用;
	不能在同一块内定义同名变量;
	本地变量不会被默认初始化;
	参数进入函数是会被初始化。
5.2 函数庶事
void f(void); 与 void f();
	在传统C中后面的表参数未知,而不是没有参数。
C语言不可以函数嵌套定义;
int main()也是一个函数;
也可以写成int main(void);
return的0有人看:
	Windows: if errorlevel 1 …
	Unix Bash: echo $?
	Csh: echo $status

6.数组

定义数组:
	<类型> 变量名称[元素数量];
	int number[100];
	double weight[20];
		元素数量必须是整数
		c99之前:元素数量必须是编译时的字面量
		c99之后:元素数量可以动态输入

数组的特点:
	其中所有元素具有相同的数据类型
	一旦创建,不能改变大小
	数组中元素在内存中连续依次排列
	使用数组需要初始化

数组中的单元:
	赋值给数组: number[num] = x;
	索引下标: grades[0];

长度为0的数组可以创建,但是没有用处
int a[0];

7.数组运算

7.1 数组的初始化
集成初始化:
	int count[] = {1,2,3,4,5,6,7,8,9,10,14,18,};

另一种写法:
	int count[num] = {0};
		数组长度为num,且内容都为0。

C99独有写法:
	int count[10] = { [4]=2,3,[8]=13 };
		给指定位置赋值,没有定位的数据接在前面的位置。
		(即3是索引为5的数据),其余位置的值补零。
		特别适合初始数据稀疏的数组。
7.2 数组的大小
int a[] = {1,2,3,4,};
printf("%d \n", sizeof(a));		//16
printf("%d \n", sizeof(a[0]));	//4
printf("%d \n", sizeof(a)/sizeof(a[0]));  //4  //推荐使用

数组不可以这样赋值
int b[] = a; //错误写法

8.二维数组

int a[3][6]
通常理解为a是一个3行6列的矩阵
8.1 二维数组的遍历
for(int i=0; i<3; i++){
	for(int j=0, j<5; j++){
		a[i][j] = i*j;
	}
}
8.2 二维数组的初始化
int a[][4] = {
	{0,1,2,3},
	{5,6,7,8},
};

* 列数必须给出,行数可以省略,由编译器来数
* 每行一个{},逗号分隔
* 如果省略元素,表示补零

9.指针

指针的&和*运算符
& 作用:获取变量的地址
* 作用:得到地址对应的值
    保存指针的变量:int *p = &i;
指针作参数
通过&符号获取地址放入参数:
    int i=0; fun(&i);
通过*符号接收指针:
    void fun(int* p);
    在函数内部可以通过这个指针访问外面。

数组变量是特殊的指针。

常见错误
定义了指针变量,还没有指向任何变量,就开始使用。
error eg:     int *p;     *p=12;

10.指针和const

指针的const的情况:
表示一旦得到某个变量的地址,则不能再指向其他变量。
    int* const q = &i;  //q是const
    *q = 19;            //ok
    q++;                //Error
所指是const的情况:
表示不能通过指针修改那个变量(不能使那个变量成为const)。
    const int *p = &i;  //(*p)是const
    *p = 19;            //Error
    i = 19;             //ok
    p = &j;             //ok
const数组保护元素:
const int a[] = {1,2,3,5,};
数组变量是const的指针,每个单元也都是const int,必须通过初始化赋值。
因为把数组传入函数时是地址,所以那个函数内部可以修改数组的值,可以设置const保护数组:
    int sum(const int a[], int length);

11.指针运算

*p++ :
    ++的优先级比*高。 常用于数组的连续空间操作。
    取出p所指的数据来,完事后顺便把p移到下一个位置去。
char ac[] = {0,1,2,3,4,5,6,7,8,9,};
char *p = &ac[0];
while(*p != -1){
    printf("%d\n", *p++);
}
for(int i=0; i<sizeof(ac)/sizeof(ac[0]); i++){
    printf("%d\n", ac[i]);
}
可以比较它们在内存中的地址;
数组中的单元的地址肯定是线性增加的;
<、<=、==、>、>=、!= 都可以对指针做;
0地址:
0地址存在,但通常是不能随便碰的地址,所以你的指针不应该有0值;
可以用0地址来表示特殊的事情:
    * 返回的指针无效的;    * 指针没有真正初始化(先初始化为0);
NULL是一个预定定义的符号,表示0地址。
指针类型及强制转换
指向不同类型的指针是不能直接互相赋值的,避免用错指针;

强制转换:int *p=&i;  void* q=(void*) p;
    void*表示不知道指向什么东西的指针;
    这并没有改变p所指的变量类型,而是用不同的眼光通过p看它所指的变量。
指针动态内存分配
#include <stdlib.h>
Format  : void* malloc(size_t size);
Example : (int*)malloc(n*sizeof(int));
    申请空间的大小以字节为单位,需要转换成想要的类型;
    如果申请失败则返回0或者NULL。

free()
    申请得来的空间需要还给系统,只能还申请来的空间的首地址。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hao难懂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值