C语言笔记(二)
复习
1、随机数
int rand(void);
生成一个 >= 0 的整型数据
int a = rand() % 51; //a的取值范围为0~50
头文件:stdlib.h
生成的随机数是伪随机数
void srand(unsigned int seed);
seed:随机数种子
time(NULL) --- 将随机数种子随着系统时间改变
#inlclude <time.h>
播下一个随机数种子
头文件:stdlib.h
2、循环语句
while
while(表达式)
{
代码块;
}
step:
先判断表达式是否为真(非0为真,0为假), 如果为真则进入循环体执行一次代码块,执行完后再次判断表达式;
如果为假,则直接跳过该循环体。
do...while
do
{
代码块;
}while(表达式);
step:
先执行代码块,再判断表达式是否问真...
for
for(表达式1; 表达式2; 表达式3)
{
代码块;
}
表达式1: 循环控制变量的初始化
表达式2: 循环退出的条件
表达式3: 循环控制变量的自增或自减
step:
先执行表达式1,再判断表达式2是否为真,如果为真则进入循环体,再执行表达式3...
如果为假,则直接跳过循环
goto
goto 一般和 if 连用
break
退出该层循环
continue
结束本次循环,并判断下一次是否进入循环
数组
- 变量定义很多,数据多
- 定义多个变量,这些变量存储在内存空间中是随机的
- 班级成绩
1、含义
- 存储大量同类型数据的有序(内存上连续)集合
2、一般形式
<存储类型> <数据类型> 数组名[元素个数];
存储类型: auto register extern static
数据类型: char short int long float double
数组名:
标识符 //满足命名规则
数组名代表整个数组空间 //sizeof(数组名) 计算整个数组空间的大小
数组名代表数组首元素地址 //数组名是一个地址常量
元素个数:
代表该数组最大能存储的元素个数
[]: 偏移并引用
定义一个数组:
char a[5]; //定义了一个char型数组,该数组最多能存储5个char型元素
int b[5];
数组元素的访问:
数组名[下标];
下标从0开始,最大为数组元素个数-1
对于数组元素的访问,一般用循环
eg:
#include <stdio.h>
int main(int argc, char *argv[])
{
int a[5];
/*
a[0] = 1;
a[1] = 2;
a[2] = 3;
printf("a[0] = %d\n", a[0]);
printf("a[1] = %d\n", a[1]);
printf("a[2] = %d\n", a[2]);
*/
int n = 0;
for(int i = 0; i < 5; i++)
{
a[i] = n;
n++;
printf("%d ", a[i]);
}
puts(" ");
printf("ip(a) = %p\n", a); //数组名是地址常量,地址常量不能赋值
printf("ip(a[0]) = %p\n", &a[0]); //数组首元素地址
printf("sizeof(a) = %ld\n", sizeof(a)); //结果为20,数组名代表整个数组空间的大小
return 0;
}
3、数组的初始化
1、完全初始化
int a[5] = {1,2,3,4,5};
char str[5] = {'h','e','l','l','o'};
= {"hello"};
= "hello";
eg:
char buf1[5] = "hello";
char buf2[5] = "world";
printf("%s\n", buf1); //打印结果为helloworld
char buf1[6] = "hello"; //字符串后有'\0', 字符数组保存字符串时,有多余的空间保存'\0'
char buf2[5] = "world";
printf("%s\n", buf1);
printf("ip(buf1) = %p\n", buf1);
printf("ip(buf2) = %p\n", buf2);
2、非完全初始化
int a[5] = {1}; //给第一个元素初始化为1,其余未初始化的元素默认值为0
int b[5] = {0}; //数组每一个元素的值都为0
3、缺省初始化
int a[] = {1,2,3,4}; //表示数组最大元素个数为4
eg1:
int a[5] = {0};
for(int i = 0; ; i++)
{
printf("%d ", a[i]);
}
//数组越界访问,可以读取未开辟空间的值,但是,访问到一定程度之后,就不允许被访问了(报段错误)
eg2:
int a[5] = {0};
for(int i = 0; i < 10; i++)
{
a[i] = i;
printf("%d ", a[i]);
}
//报段错误,不能修改未开辟空间中的数据
易错点:
int a[5] = {0};
int b[5];
b = a; //错误,不能通过一个已定义数组赋值给新的数组,数组名是地址常量
a[5] = {1,2,3}; //error a[5]在定义之后单独使用,代表某一个元素
int i;
int a[i]; //变量不能作为数组初始化的元素个数
练习:从键盘上输入十个分数(是个评委), 去掉最高分、最低分,输出分数的平均值。
#include <stdio.h>
int main(int argc, char *argv[])
{
int a[10] = {0};
for(int i = 0; i < 10; i++)
{
scanf("%d", &a[i]);
}
int max = a[0];
int min = a[0];
int sum = 0;
for(int i = 0; i < 10; i++)
{
sum += a[i];
if(max < a[i])
max = a[i];
if(min > a[i])
min = a[i];
}
printf("max = %d min = %d ave = %d\n", max,min,(sum - max - min)/8);
return 0;
}
冒泡排序
从键盘输入一组数据,保存在数组中,使用冒泡排序对该数组中的元素排序(从小到大)
eg:
#include <stdio.h>
int main(int argc, char *argv[])
{
int a[5] = {0};
for(int i = 0; i < 5; i++)
{
scanf("%d", &a[i]);
}
for(int i = 0; i < 4; i++)
{
for(int j = 0; j < 4 - i; j++)
{
if(a[j] > a[j + 1])
{
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
for(int i = 0; i < 5; i++)
{
printf("%d ", a[i]);
}
puts(" ");
return 0;
}
字符串操作函数
1、strlen
函数原型
size_t strlen(const char *s);
功能:
计算s所指向的字符串的长度
参数:
const char *s;
待计算的字符串的地址
返回值:
返回该字符串的有效长度,不包括'\0';
头文件:
#include <string.h>
eg:
char str[10] = "hello";
printf("sizeof(str) = %ld\n", sizeof(str)); // 10 sizeof计算整个数组空间的大小
printf("strlen(str) = %ld\n", strlen(str)); // 5 strlen计算有效字符的个数
注意:strlen函数,遇见'\0'就会结束
练习:输入一个字符串,将其逆序输出
2、strcpy
函数原型
char *strcpy(char *dest, const char *src);
功能:
将src所指向的字符串(包括'\0'),拷贝到缓冲区dest中
参数:
char *dest : 缓冲区
const char *src : 待拷贝的字符串地址
返回值:
返回dest缓冲区的地址
头文件:
#include <string.h>
eg:
char dest[20] = {0};
strcpy(dest, "hello");
puts(dest);
3、strcat
函数原型
char *strcat(char *dest, const char *src);
char *strncat(char *dest, const char *src, size_t n);
功能:
把src所指向字符串连接在dest缓冲区中的字符串后面,src要覆盖掉dest缓冲区中的'\0',并在新的字符串后面加上'\0'
参数:
char *dest : 缓冲区
const char *src : 待连接的字符串地址
返回值:
返回dest缓冲区的地址
头文件:
#include <string.h>
eg:
char dest[20] = "hello";
char src[20] = "world";
strcat(dest, src);
puts(dest);
4、strcmp
函数原型
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
功能:
比较s1与s2两个字符串的大小,从左至右依次判断
参数:
const char *s1: 字符串首地址
const char *s2: 字符串首地址
返回值:
> 0 : s1 > s2
< 0 : s1 < s2
= 0 : s1 = s2
头文件:
#include <string.h>
eg:
int cmp = strcmp("abc", "abb");
if(cmp > 0)
printf("abc > abb\n");
else if(cmp < 0)
printf("abc < abb\n");
else
printf("abc = abb\n");
Day7
复习
数组
1、存储大量同类型数据,并且数据在内存空间中是连续存储的
2、数组的定义
<存储类型> <数据类型> 数组名[元素个数];
存储类型:默认为auto
数据类型: char short int long float double
数组名:
标识符 //满足命令规则
代表整个数组空间 //sizeof(数组名) 求整个数组空间的大小 = 元素个数 * sizeof(数据类型)
代表数组首元素的地址 //数组名是一个地址常量
元素个数:
决定数组最大能存放的元素个数
[]: 偏移并引用
3、数组的使用
数组名[下标];
下标:从0开始,最大为数组元素-1
int a[4];
a[0] = {1};
一般使用循环语句便利数组
4、数组的初始化
完全初始化:
int a[3] = {1,2,3};
非完全初始化:
int b[4] = {1}; //未被初始化的元素值为0
int c[4] = {0}; //将该数组元素全部赋值为0
缺省初始化:
int d[] = {1,2,3,4};
冒泡排序
字符串数组
char str[10] = {"hello"};
= "hello";
= {'h','e','l','l','o'};
字符串末尾有'\0'
字符串操作函数
1、strlen
函数原型:
size_t strlen(const char *s);
函数功能:
计算字符串的有效长度,不包括'\0'
返回值:
字符串的有效长度
参数:
字符串首地址
头文件:
#inlcude <string.h>
2、strcpy
函数原型:
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
函数功能:
把字符串src复制到缓冲区dest中,包括'\0';
返回值:
dest缓冲区的首地址
参数:
字符串src首地址
dest缓冲区首地址
头文件:
#inlcude <string.h>
3、strcmp
函数原型:
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
函数功能:
从左至右依次比较s1和s2的元素
返回值:
> 0 : s1 > s2
< 0 : s1 < s2
= 0 : s1 = s2
参数:
字符串s1 s2首地址
头文件:
#inlcude <string.h>
4、strcat
函数原型:
char *strcat(char *dest, const char *src);
char *strncat(char *dest, const char *src, size_t n);
函数功能:
将src字符串拼接在dest缓冲区后,要覆盖dest末尾的'\0'
返回值:
dest缓冲区首地址
参数:
字符串dest src首地址
头文件:
#inlcude <string.h>
多维数组 – 二维数组
多个一维数组
1、二维数组的定义
<存储类型> <数据类型> 数组名[行][列];
存储类型:默认为auto
数据类型:char short int long float double
数组名:
标识符
二维数组首行地址
代表二维数组整个数组空间 // sizeof(二维数组名)
行数:
列数:
二维数组元素个数: 行 * 列
整个二位数组空间大小: 行 * 列 * sizeof(二维数组数据类型)
eg:
int arr[2][3];
2、二维数组的存储方式
在内存中线性存储,抽象化出行列
3、二维数组的访问
数组名[行下标][列下标];
行下标和列下标都是从0开始,最大为行数-1 列数-1
int a[2][3];
a[0][1] = 1;
使用嵌套循环对二维数组进行遍历
eg:
int main()
{
int a[2][3];
srand(time(NULL));
//循环遍历赋值
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 3; j++)
{
a[i][j] = rand() % 51; //生成0~50的随机整数
}
}
//循环遍历打印
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 3; j++)
{
printf("%d ", a[i][j]);
}
puts(" ");
}
return 0;
}
4、二维数组的初始化
完全初始化
int a[2][3] = {1,2,3,4,5,6};
int a[2][3] = {{1,2,3}, {4,5,6}};
非完全初始化
int a[2][3] = {1,2,3}; //未初始化的元素默认为0
int a[2][3] = {{1,2}, {4,5}};
缺省初始化
int a[][] = {1,2,3,4,5,6,7,8}; //error
int a[2][] = {1,2,3,4,5,6,7,8}; //error
int a[][3] = {1,2,3,4,5,6,7,8}; //right 3*3的二维数组
练习:实现一个二维数组的转置
找出一个3行4列二维数组中的最大的元素,并打印该元素的行和列
打印杨辉三角形的前10行
指针
1、什么是指针
- 指针就是地址的别名
- 什么是地址
- 内存由多个内存单元构成,每个内存单元由一个或者多个字节组成,每一个字节都有一个编号,这个编号就是地址
- 指针变量,用来保存一个地址常量
- 指针、地址、指针变量,为了方便理解,把指针、地址、指针变量都叫做指针
2、指针变量的定义
<存储类型> <数据类型> *指针变量名;
存储类型
数据类型: char int ....
* : 表示该变量是一个指针变量
指针变量名: 标识符
eg:
int *p; //定义一个指针变量p
指针变量的赋值:
eg1:
int a = 10;
int *p;
p = &a; //将变量a的地址值赋值给指针变量p
eg2:
int arr[5] = {1,2,3,4,5};
int *q;
q = arr;
指针的初始化:
int a = 10;
int *p = &a; //指针的初始化
int *q = NULL;
NULL //代表零地址空间,不可读也不可写,NULL是零地址空间的宏定义
3、指针变量的大小
指针变量占一定的空间大小
int *q;
sizeof(q); //8
char *p;
sizeof(p); //8
在32位机中,指针变量的大小为4字节
在64位机中,指针变量的大小为8字节
4、直接访问与间接访问
- 直接访问:通过变量的地址直接访问该变量
- 间接访问:通过保存该变量地址的变量(指针变量)去访问该变量
4、&与*
* :在定义变量时,代表定义的是一个指针变量
表示乘法符号
在对一个指针变量使用时,表示取该指针所指向的地址空间的内容(取内容)
*p :取p指针所指向空间的内容
&:取地址符号
获取变量的地址
eg:
int a = 10;
int *p = &a;
printf("a = %d\n", a);
printf("a = %d\n", *p); //*p取p指针所指向地址空间的内容,现目前p所指向的空间为变量a的地址空间,所有可以打印变量a的值
int arr[4] = {1,2,3,4};
int *q = arr;
printf("arr[0] = %d\n", arr[0]);
printf("arr[0] = %d\n", *q);
5、指针的运算
指针的算术运算
指针的偏移是以数据类型为单位进行偏移
指针的数据类型由该指针所指向空间的数据类型决定
int a = 10;
int *p = &a;
p + 1; //以int数据类型的大小为单位移动 -- 四个字节
p + n: 指针向地址高的方向移动n个数据
数据: 不同的数据类型,指针移动的字节数不一样
p + 1: 指针向地址高的方向移动 1 个数据
p - 1: 指针向地址低的方向移动 1 个数据
p + 1 与 p++ 、 ++p 的区别
p + 1 : 如果没有重新对指针赋值,则指针的地址值不会改变(指针的指向)
p++ : p = p+1 //对指针变量重新赋值
++p 和 p++ 的区别
如果单独使用,是对指针本身进行自增
p++;
++p;
int a[4] = {1,2,3,4};
int *p = a;
printf("ip(p) = %p\n", p);
printf("ip(++p) = %p\n", ++p); //打印的地址值偏移4字节
printf("ip(p) = %p\n", p);
printf("ip(p) = %p\n", p);
printf("ip(p++) = %p\n", p++); //打印的地址值未偏移
printf("ip(p) = %p\n", p);
*p++ 和 *(p++)
int a[4] = {1,3,5,7};
int *p = a;
//printf("*p++ = %d\n", *p++); //打印第一个元素的值 1
printf("*(p++) = %d\n", *(p++)); //打印第一个元素的值 1
*p++ *(p++) 本质上没有区别
使用指针实现字符串逆序输出
day8
复习
二维数组
1、二维数组的定义
<存储类型> <数据类型> 二维数组名[行][列];
存储类型: 默认auto
数据类型: char int short....
二维数组名:
标识符
代表整个二维数组空间 //sizeof(二维数组名)
代表二维数组首行的地址
二维数组最大存储元素个数:行 * 列
int arr[2][3];
2、二维数组的使用
数组名 [行下标][列下标];
行下标和列下标都从0开始,最大为行数和列数-1
int arr[2][3];
arr[0][0] = 1; //将二维数组的第一个元素赋值为1
一般用嵌套for循环遍历二维数组
srand(time(NULL));
//循环给二维数组每一个元素赋值
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 3; j++)
{
arr[i][j] = rand() % 51;
}
}
3、二维数组在内存中是连续存储的(线性)
4、二维数组初始化
完全初始化
int arr[2][3] = {1,2,3,4,5,6};
int arr[2][3] = {{1,2,3},{4,5,6}};
非完全初始化
int arr[2][3] = {1,2,3};
int arr[2][3] = {{1,2},{4,5,6}};
缺省初始化
int arr[][3] = {1,2,3,4,5}; //必须确定列数
指针
-
什么是指针
- 指针就是地址,地址的别名
-
什么是地址
- 内存是由多个内存单元组成的,内存单元是由一个或多个字节构成,每个字节都有一个编号,这个编号就叫做地址
指针变量:用来保存地址值
1、指针变量的定义
<存储类型> <数据类型> *指针变量名;
*: 表示定义时,该变量是一个指针变量
int a = 10;
int *p = &a;
int arr[3] = {0};
int *q = arr;
int *m; //m是一个野指针
数据类型: 指针的数据类型,根据指针所指向地址空间的数据类型定义
2、指针的初始化
int arr[3] = {0};
int *q = arr; //定义时就指明指针的指向
3、指针的大小
sizeof(指针变量名) --> 8字节
64位机中,指针的大小为 8 字节
32位机中,指针的大小位 4 字节
4、& 和 *
&: 取地址
*: 取内容,取该指针所指向地址空间的内容
乘法符号
5、指针的运算
p + 1 : 地址向高位增加1个数据(以该数据的数据类型大小为单位+1)
p + N : 地址向高位增加N个数据(以该数据的数据类型大小为单位+N)
p - 1 : 地址向高位减少1个数据(以该数据的数据类型大小为单位-1)
p - N : 地址向高位减少N个数据(以该数据的数据类型大小为单位-N)
p++ 和 ++p
单独使用: 该指针p偏移一个数据类型的大小,指针指向改变
复杂运算: 后++ 在一句代码结束后,再改变指针的指向
*p++ *(p++)
先取该指针所指向地址空间的内容,再进行指针的偏移
*++p *(++p)
p先偏移,再取该指针所指向地址空间的内容
1、空指针
char *p = NULL; //空指针
NULL是一个宏定义,代表零地址空间,零地址空间,不可读不可写
为了防止指针成为野指针
2、void指针
void指针也叫做万能指针
int a = 10;
void *p = &a;
void指针可以用来保存任何数据类型的地址
void指针在使用时,要强转为相应的数据类型
int a = 10;
void *p = &a;
printf("%d\n", *(int *)p);
3、指针指向字符串
char *p = "hello";//p指向的是一个字符串常量的首地址
*p = 'a'; //error不能改变常量区的内容
char str[] = "hello";
char *p = str;
*p = 'a';
可以通过指针修改字符串数组中的内容
4、const修饰指针
int a = 10;
const int *p = &a;
const修饰*p:
该指针指向地址空间的内容不能被修改,但是可以改变指针的指向
int a = 10;
int * const p = &a;
const修饰p:
该指针的指向不能修改,但是可以修改指针所指向地址空间中的内容
int a = 10;
const int * const p = &a;
练习:
-
用一级指针遍历二维数组,并打印
-
用指针实现字符串的压缩
- AAAbbbcccderr —> Abcder
-
输入一个"12345",转换成整型数据12345输出
-
用一级指针实现二维数组的冒泡排序
Day 9
1、多级指针
- 指向一个指针变量的地址的指针,叫多级指针
2、二级指针
- 指向一个一级指针地址
1、二级指针的定义
<存储类型> <数据类型> ** 指针变量名;
int **pp; //pp是一个二级指针
eg:
int a = 10;
int *p = &a;
int **pp = &p;
printf("%ld\n",sizeof(pp));
printf("%ld\n",sizeof(int **));
printf("&a = %p\n", &a);
printf("p = %p\n", p);
printf("*pp = %p\n", *pp);
printf("**pp = %d\n", **pp);
printf("pp = %p\n", pp);
printf("pp + 1 = %p\n", pp + 1);
3、数组指针
是一个指针,指向数组一行的指针,也可以叫行指针
1、数组指针的定义
<存储类型> <数据类型> (*指针变量名)[一行元素个数];
int a[5] = {1,2,3,4};
int *p = a;
int (*q)[4] = &a;
for(int i = 0; i < 4; i++)
{
printf("%d ", *(*q + i));
}
puts(" ");
printf("*q = %p\n", *q);
printf("*q + 1 = %p\n", *q + 1);
printf("*(*q) = %d\n", *(*q));
printf("a = %p\n", a);
printf("a + 1 = %p\n", a + 1);
printf("&a = %p\n", &a);
printf("&a + 1 = %p\n", &a + 1);
2、数组指针指向二维数组
int a[2][3] = {1,2,3,4,5,6};
int (*p)[3] = a;
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 3; j++)
{
printf("%d ", *(*(p + i) + j));
}
puts(" ");
}
3、二维数组元素、地址表示
int a[2][3] = {1,2,3,4,5,6};
int (*p)[3] = a;
printf("a[0][0] = %d\n", a[0][0]);
printf("p[0][0] = %d\n", p[0][0]);
printf("*(*(p + 0) + 0) = %d\n", *(*(p + 0) + 0));
printf("*(*(a + 0) + 0) = %d\n", *(*(a + 0) + 0));
printf("a[1][1] = %d\n", a[1][1]);
printf("p[1][1] = %d\n", p[1][1]);
printf("*(*(p + 1) + 1) = %d\n", *(*(p + 1) + 1));
printf("*(*(a + 1) + 1) = %d\n", *(*(a + 1) + 1));
printf("*(p[1] + 1) = %d\n", *(p[1] + 1));
printf("*(p[1] + 1) = %d\n", (*(p + 1))[1]);
*(*(p + 1) + 1) <==> a[1][1] <==> p[1][1] <==> *(*(a + 1) + 1)
*(p[1] + 1) <==> *(a[1] + 1) <==> (*(p + 1))[1] <==> (*(a + 1))[1]
4、指针数组
本质就是一个数组,存放大量相同类型的指针变量
1、指针数组的定义
<存储类型> <数据类型> *变量名[元素个数];
int *pArr[3];
2、指针数组元素访问
指针数组名[下标];
int a = 10;
int b = 20;
int c = 30;
char d = 's';
//定义一个指针数组,分别保存变量a b c的地址
int *pArr[3] = {&a, &b, &c};
3、指针数组的使用
int *parr[3] = {NULL};
char *pArr[3] = {"hello","world","!"};
int n = 0;
while(n < 3)
{
puts(pArr[n]);
printf("%p\n",pArr[n]);
n++;
}
printf("%c\n", *(pArr[0] + 1));
*pArr[0] = 'l';
printf("%c\n", *pArr[0]);
//用二级指针保存指针数组的
char **p = pArr;
练习:
利用指向行的指针变量求5×3数组各行元素之和。
编写一个程序,输入星期,输出该星期的英文名。用指针数组处理
Monday Tuesday Wednesday Thursday Friday Saturday Sunday
Day10
1、main函数参数
#include <stdio.h>
int main(int argc, char *argv[])
{
//argc 和 argv都是命令行参数
//argc 表示命令行参数的个数
//argv 是一个指针数组,用来保存命令参数的地址
printf("argc = %d\n",argc);
for(int i = 0; i < argc; i++)
{
puts(argv[i]);
}
return 0;
}
2、函数
- 实现某个特定功能的代码模块
- 使得代码简洁,清晰
1、函数的定义
<返回类型> 函数名(形参列表)
{
函数体;
return 返回值;
}
返回类型:
一般数据类型: char short int float double long
指针类型: char *, short *, int *, float *....
空类型: void 代表这个函数没有返回值
void func()
{
return;
}
函数的返回类型,必须和函数返回值的类型相同
函数名:
标识符
函数的入口地址
形参列表:
可以没有,也可以定义不同数据类型的参数(不能初始化), 多个参数用 , 隔开
函数体:
实现功能的代码块;
return:
return 代表一个函数的结束
返回值:
函数调用的时候,返回值的数据类型要与函数 <返回类型> 相同
函数三要素:函数的返回的类型、形参列表、函数的返回值
[1] 定义一个函数,实现打印n行hello world
void my_print(int n)
{
for(int i = 0; i < n; i++)
printf("hello world\n");
}
[2] 判断两个整型数据中最大的值,并返回最大数值
int max(int a, int b)
{
if(a > b)
return a;
else
return b;
}
[3] 封装一个函数,求n的阶乘
int mul(int n)
{
int sum = 1;
if(n == 0 || n == 1)
return 1;
if(n > 1)
{
while(n)
{
sum *= n;
n--;
}
}
return sum;
}
2、函数的声明
告知编译器在别处定义的函数要在后续程序使用
<返回类型> 函数名(形参列表);
形参列表也可以只写参数的数据类型
函数的声明放在函数调用之前都可以,一般放在头文件和主函数的中间,也可以放在头文件中
3、函数的调用
函数名(实参列表);
4、函数参数传递
值传递
将实参的值拷贝一份给形参,形参的改变不会影响实参的值
地址传递
将实参的地址传递给形参,所以可以通过该地址改变实参的值
练习:封装一个函数,打印一维数组
//函数声明
void print_arr(int len, int *s);
int main(int argc, char *argv[])
{
int a[5] = {1,2,3,4,5};
//函数调用
//print_arr(5, a);
print_arr(sizeof(a)/sizeof(a[0]), a);
//sizeof(a)/sizeof(int) 计算数组大小
return 0;
}
//定义一个函数,打印一维数组元素,参数传入数组大小 len 数组首地址 s
//void print_arr(int len, int s[])
void print_arr(int len, int *s)
{
for(int i = 0; i < len; i++)
printf("%d ", s[i]);
puts(" ");
}
作业:封装函数,实现strcmp功能