作业:
- 使用数组作为参数传递,完成一维数组的输入和输出,写两个函数,一个输入一个输出。
- 定义一个字符数组,作为参数传递,完成strlen函数的功能,定义一个int my_strlen(const char *p){}
- 整理思维导图
- 使用指针指向字符串的方式,写一个函数完成删除字符串中的空格
#include <stdio.h> #include <stdlib.h> #include <string.h> int m = 10; int n = 20; //功能:实现 p 指向的地址的值变为 n 的地址 int myfunc1(int **q){ int temp = 0; *q = &n; } //功能:实现两个数 值 的交换 void swap(int *p1,int *p2){ int temp = 0; temp = *p1; *p1 = *p2; *p2 = temp; } //功能:实现一维数组的终端输入 void myfunc2(int *p,int len){ int i = 0; for(i = 0;i < len;i++){ scanf("%d",p+i); } for(i = 0;i < 5;i++){ printf("%d\t",p[i]); } printf("\n"); } //功能:实现strlen功能,计算字符串的长度 int my_strlen(const char *p){ int count = 0; while(*p){ count++; p++; } return count; } //功能:删除字符串中的空格 void myfunc3(char *p){ int i = 0; int count = 0; int len = strlen(p); while(*(p+i)){ i++; } for(i = 0;i < len;i++){ if(*(p+i) != ' '){ *(p+count) = *(p+i); count++; } } *(p+count) = *(p+i); } int main(int argc, const char *argv[]) { #if 0 int *p = &m; printf("p = %p &m = %p\n",p,&m); myfunc1(&p); printf("p = %p &n = %p\n",p,&n); #endif #if 0 int a = 10; int b = 20; printf("a = %d b = %d\n",a,b); swap(&a,&b); printf("a = %d b = %d\n",a,b); #endif #if 0 int arr[5] = {0}; myfunc2(arr,5); #endif #if 0 char s1[32] = "hello world"; int ret = my_strlen(s1); printf("strlen(s1) = %d\n",ret); #endif #if 1 char s2[32]= {0}; gets(s2); myfunc3(s2); puts(s2); #endif return 0; }
- 猴子吃桃问题,猴子第一天摘了若干个桃,当即就吃了一半数量的桃,没吃过瘾,又多吃一个,第二天,在剩下的桃里有吃了一半数量的桃,没吃过瘾,又多吃了一个,依此类推,直到第10天,想吃桃的时候,发现只剩下一个桃了,问:猴子第一天摘了多少个桃。while循环实现
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, const char *argv[]) { int num = 1; int day = 1; while(day < 10){ num = 2 * (num + 1); day++; } printf("num = %d\n",num); return 0; }
- 实现atoi函数
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, const char *argv[]) { char s[32] = {0}; gets(s); char *p = s; int num = 0; while(*p){ num *= 10; num += *p - '0'; p++; } printf("%d\n",num); return 0; }
- 整理函数的值传递和地址传递 画图理解
一、函数
面向对象语言:C++,封装性好
面向过程语言:C语言,封装性更差一些,代码的复用性差
函数在C语言中,提高代码的复用性。
【1】概念
函数:指的是实现特定功能的代码块。
【2】定义
返回值类型 函数名(形式参数列表)
{
//实现函数功能的代码块;
return 返回值;
}
返回值类型,决定了函数返回的结果;函数的返回值可以有,也可以没有,如果返回值类型是void,可以不写return
函数名:也是一个标识符,给函数起的名字(写什么都可以)
(形参列表):用于获取外部传递过来的参数的,函数是否有形参,根据函数功能来决定,如果没有形参,()中可以什么都不写,也可以写void
返回值:函数运行结束,返回给调用处的结果,根据函数的需求,如果调用函数的位置需要返回值,在函数内部就需要写返回值
如果调用处不需要返回值,返回值类型可以写成void
【3】函数的分类
i)有参有返回值函数
//实现有参有返回值的加法函数
//返回加法的结果
int add(int a,int b)
{
return a+b;
}
ii)有参无返回值函数
//有参无返回值函数
void mul(int a,int b)
{
printf("mul=%d\n",a*b);
}
iii)无参无返回值函数
//无参无返回值函数
void fun()
{
printf("1\n");
}
iv)无参有返回值函数
//无参有返回值函数
int my_getchar()
{
return getchar();
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//实现有参有返回值的加法函数
//返回加法的结果
int add(int a,int b)
{
return a+b;
}
//有参无返回值函数
void mul(int a,int b)
{
printf("mul=%d\n",a*b);
}
//无参无返回值函数
void fun()
{
printf("1\n");
}
//无参有返回值函数
int my_getchar()
{
return getchar();
}
int main(int argc, const char *argv[])
{
printf("%d\n",add(3,5));
mul(2,4);
fun();
char c = my_getchar();
printf("%c\n",c);
return 0;
}
【4】函数的调用
在其他函数中使用功能函数
函数名(实参);
//如果函数没有参数列表()里面的内容不写
【5】函数的声明
函数声明的时机: 如果被调函数定义在主调函数的下方,由于程序顺序执行,在调用时并没有定义过被调函数
程序会报警告,再调用函数前,添加函数的声明就可以消除警告
函数声明的格式:
返回值类型 函数名(形参的类型);
简单的办法:直接把定义函数的函数头拿到主调函数上方
函数声明的作用:告诉编辑器,已经定义过该函数,还要告诉编辑器函数的返回值类型和形参类型
函数声明的位置:头文件的下方,主调函数的上方(保证在调用之前声明过该函数)
【6】全局变量和局部变量
全局变量:没有定义在任何函数内的变量(没有被包在任何{}里面的变量)
全部变量:定义在函数中的变量
全局变量和局部变量,生命周期和作用域是不同的
生命周期:分配的空间何时被回收,变量的开始到消亡
作用域:可以访问的范围
存储类型:6种
auto:局部变量默认是auto,全局变量不能使用auto修饰
static:修饰局部变量时,延长局部变量的生命周期
修饰全局变量时,限制全局变量只能在当前文件中被访问
static修饰的变量只会被初始化一次
extern: 引入外部文件种的变量
register:
const:一般不对const修饰的变量取地址
volatile:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//auto int num = 90; error全局变量不能使用auto修饰
static int num = 90; //全局变量的生命周期和作用于是整个程序的开始到结束
int num2; //静态区中, .bss段中
int fun();
void out(); //外部文件中函数的声明
int main(int argc, const char *argv[])
{
auto int sum=100;
//main里面的sum是局部变量,但是由于main函数是程序的入口,定义在main函数中变量的生命周期和全局变量的一样长
//作用域只能在主函数内被访问
int ret1 = fun(); //7
int ret = fun(); //9
printf("16=%d\t17=%d\n",ret1,ret);
return 0;
}
int fun()
{
int a; //变量a的生命周期和作用于再fun函数内
static int b; //变量b的生命周期是程序的开始到结束但是作用域仍然是fun函数内
static int var = 5; //static修饰的变量生命周期是程序开始到结束,所以static修饰的变量支部会被初始化一次
int i=0;
while(i<2)
{
i++;
var++;
}
return var;
//printf("%d\n",sum); sum的作用域只在主函数中
}
【7】函数的值传递和地址传递
函数传参,就是使用实参初始化形参的过程。
i)值传递
值传递,单纯把实参的值传递给形参的过程
如果是指传递,函数内部无法修改实参的值
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int var1=80;
int var2=90;
int add(int a,int b);
void swap(int a,int b); //swap的前置声明
int main(int argc, const char *argv[])
{
int ret = add(var1,var2); //全局传参
printf("%d\n",ret);
int num1=90,num2=39;
printf("num1=%d\tnum2=%d\n",num1,num2); //90,39
swap(num1,num2);
printf("num1=%d\tnum2=%d\n",num1,num2);
return 0;
}
int add(int a,int b)
{
return a+b;
}
void swap(int a,int b)
{
int temp;
temp = a;
a = b;
b = temp;
}
ii)地址传递
地址传递,就是是用实参地址初始化形参
如果是地址传递,函数内可以改变实参的值
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int var1=80;
int var2=90;
int add(int a,int b);
void swap(int *a,int *b); //swap的前置声明
int main(int argc, const char *argv[])
{
int ret = add(var1,var2); //全局传参
printf("%d\n",ret);
int num1=90,num2=39;
printf("num1=%d\tnum2=%d\n",num1,num2); //90,39
swap(&num1,&num2);
printf("num1=%d\tnum2=%d\n",num1,num2);
return 0;
}
int add(int a,int b)
{
return a+b;
}
void swap(int *a,int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
【8】一维整形数组作为函数传参
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//一维整型数组作为参数传递,需要传数组的首地址,还要传数组的长度
//5没有任何含义,代码的自注释,给程序自己看数组有多长
//void fun(int p[5],int len)
void fun(int *p,int len)
{
printf("%ld\n",sizeof(p)); //8,p就是一个指针,只是写成了数组的形式
//arr的终端输入
int i;
for(i=0;i<len;i++)
{
scanf("%d",p+i);
}
}
int main(int argc, const char *argv[])
{
int arr[5];
fun(arr,5);
int i;
for(i=0;i<5;i++)
{
printf("arr[%d]=%d\n",i,arr[i]);
}
return 0;
}