复习
函数(把一些完成一个特定功能的代码集合到一起,变成一个函数)
*
***
*****
*
***
*****
void print_star() //函数定义
{
printf(" *\n");
printf("***\n");
printf("*****\n");
}
int main()
{
print_star();
}
带参数,返回值的函数
求最大值
int max(int a, int b)
{
returna > b ? a : b;
}
int main()
{
intx = max(3, 5); //3---> a 5---> b
}
指针(指针变量: 保存一个地址)
int a = 10;
int *p;
p = &a;
*p = 20;
指针也可以指向一个数组
int a[5] = {10, 20, 30, 40, 50};
int *p;
p = a;
*(p + 1) = a[1];
*(p + 2) = a[2];
....
指针可以作为函数的参数
求n个学生的学生成绩总和
int get_sum(int *p, int n)
{
inti, sum = 0;
for(i= 0; i < n; i++)
{
sum+= *(p + i); //sum += p[i];
}
returnsum;
}
int main()
{
inta[] = {90, 80, 70, 60, 50};
intx = get_sum(a, 5);
}
作业讲解
作业:1 完成一个函数,输出
*
***
*****
*******
*********
#include <stdio.h>
void print_star(int n)
{
inti, j;
for(i= 0; i < n; i++) //有n层
{
//先输出空格
for(j= 0; j < n - i - 1; j++)
printf("");
//再输出星号
for(j= 0; j < 2 * i + 1; j++)
printf("*");
printf("\n");//输出换行
}
}
int main()
{
intn;
scanf("%d",&n);
print_star(n);
}
作业:2 完成字符串拷贝函数 mystrcpy(char *dst, char *src); //src (source 源头) dst(destination 目标)
#include <stdio.h>
void my_strcpy(char *dst, char *src)
{
while(*src!= '\0')
{
*dst = *src;
dst++;
src++;
}
*dst= '\0';
}
int main()
{
chara[] = "hello world"; //字符串有结束符'\0'
charb[100] = { 0 };
my_strcpy(b,a); //会将a字符串中的数据copy给 b
printf("bis %s\n", b);
}
void my_strcpy(char *dst, char *src)
{
inti = 0;
while(src[i]!= '\0')
{
dst[i]= src[i];
i++;
}
dst[i]= '\0';
}
void my_strcpy(char *dst, char *src)
{
while(*dst++= *src++); //linux源码, '\0' ====== 0
//1) *dst = *src //先赋值
//2) while(*dst) // 只要*dst 非0, 就继续执行
//3) src++, dst++
}
//linux源码, '\0' ====== 0
ascii码为0 数值0 字符‘0’是48
选择题
inta = 0;
while(a= 1) //1) a = 1 2) while(a)
{
printf("1111\n");
}
A 循环一次也不执行 B 循环执行一次 C 无限循环
int main()
{
chara[] = "hello world"; //字符串有结束符'\0'
charb[100] = { 0 };
my_strcpy(b,a); //会将a字符串中的数据copy给 b
printf("bis %s\n", b);
}
//指针的算术运算
+ - * / % ++ -- +1
两个指针不可以+ * / %, 但是可以 - 减
#include <stdio.h>
int main()
{
inta[5] = {10, 20, 30, 40, 50};
int*p = &a[0];
int*q = &a[2];
printf("%d\n",p + q); //两个指针不能加(因为两个地址相加完全没有任何意义)
printf("%d\n",q - p); //A ???? A 2 B 8 (两个指针相减,能算出 两个指针变量差有多少个元素)
printf("%d\n",*q - *p); //20(值相减)
}
p + 1 ????? (难点)
#include <stdio.h>
int main()
{
inta[5] = {10, 20, 30, 40, 50};
int*p = a;
charb[] = "hello";
char*q = b;
//假设 a (0x0000 1100) b(0x0000 2200)
printf("pis %p, q is %p\n", p, q);
p++; //p ? p 加多少由 p指向的变量的类型决定(int a + sizeof(int) 4)
q++; //q ? (chara + sizeof(char) 1)
printf("pis %p, q is %p\n", p, q);
}
//指针的关系运算
指针 > < == !=
== 是什么意思(如果两个指针相等,说明他们共同指向了一个变量)
#include <stdio.h>
int main()
{
inta[5] = {10, 20, 30, 40, 50};
int*p = a;
int*q = a;
if(p== q)
{
printf("pand q point same\n");
}
else
{
printf("different\n");
}
}
//空指针 : 在 c语言中用 NULL 代表空指针
用法:
#include <stdio.h>
int main()
{
int*p; //p 因为没指向有效变量,又被称为野指针
*p= 20;
printf("*pis %d\n", *p);
}
//Segmentation fault (core dumped) 段错误
//如果 使用了一个非法内存,就出这个错误
1) 数组越界 int a[10]; a[100]= 99; //越界,因为a只有10个元素
2) 使用了一个指针,但是未初始化,直接 *p 操作
为了避免野指针,通常在 p 不知道该指向谁时,那么赋值为 NULL
#include <stdio.h>
int main()
{
int*p = NULL; //避免野指针
if(p!= NULL)
{
*p= 20;
printf("*pis %d\n", *p);
}
}
练习
1 写一个函数,计算数组中成绩小于60的人数
#include <stdio.h>
int get_low_60(int *p, int n)
{
inti, sum = 0;
for(i= 0; i < n; i++)
{
if(p[i]< 60)
{
sum++;
}
}
returnsum;
}
int main()
{
inta[10] = {60, 20, 30, 40, 50, 76, 69, 85, 73, 72};
intx = get_low_60(a, 10);
printf("xis %d\n", x); //5
}
2 写一个函数,查找一个字符串中某个字母出现的次数
#include <stdio.h>
int find_word(char *p, char c)
{
intj = 0;
while(*p!= '\0')
{
if(*p== c)
{
j++;
}
p++;
}
returnj;
}
int main()
{
chara[] = "hello world";
intx = find_word(a, 'l');
printf("xis %d\n", x); //3
}
3 编写一个函数,完成下面功能,能将Hello World! 转换成Lipps Asvph!
#include <stdio.h>
void change_passwd(char *p)
{
while(*p!= '\0')
{
if((*p>= 'a' && *p <= 'v') || (*p >= 'A' && *p <= 'V') )
{
*p= *p + 4;
}
elseif((*p >= 'w' && *p <= 'z') || (*p >= 'W' && *p <='Z'))
{
*p= *p + 4 - 26;
}
p++;
}
}
int main()
{
charpasswd[] = "Hello World!";
change_passwd(passwd);
printf("%s\n",passwd); //Lipps Asvph!
}
如果想实现用一个函数,交换两个数
//写一个swap, 交换两个数
#include <stdio.h>
void swap(int a, int b) //a 和 b交换了,但x, y没换
{
intt;
t= a;
a= b;
b= t;
}
int main()
{
intx = 5, y = 9;
swap(x,y); //交换x 和 y
printf("xis %d, y is %d\n", x, y); //x is 9, yis 5
}
函数参数值传递,无法改变实参的值
/那么上面的问题就可以采用地址传递
#include <stdio.h>
void swap(int *a, int *b) //
{
intt;
t= *a;
*a= *b;
*b= t;
}
int main()
{
intx = 5, y = 9;
swap(&x,&y); //x 的地址给 a, y 的地址 给b
printf("xis %d, y is %d\n", x, y); //x is 9, yis 5
}
函数参数传递,有两种方式
///值传递,改变不了实参的值,就是把实参的值传递给形参,然后形参 进行运算
///地址传递,可以改变实参的值,形参是一个指针变量,实参传递的是变量的地址(形参通过地址间接改变形参的值)
练习1
编写函数fun:从n个学生的成绩中统计出低于平均分的学生人数,由函数值返回,
平均分存放在形参*ptr_aver所指的存储单元中(即平均分由参数返回)。
函数原型为:int fun( float *s, int n, float*ptr_aver );
例如:若输入8名学生的成绩如下
80.5 60 72 90.5 98 51.5 88 64
则低于平均分的学生人数为:4(平均分:75.5625)。
#include <stdio.h>
int fun(float *s, int n, float*ptr_aver)
{
floatsum = 0;
inti = 0, count = 0;
for(i= 0; i < n; i++)
{
sum+= s[i]; //sum += *(s + i);
}
*ptr_aver= sum / n;
for(i= 0; i < n; i++)
{
if(s[i]< *ptr_aver)
count++;
}
returncount;
}
int main()
{
floata[8] = {80.5, 60, 72, 90.5, 98, 51.5, 88, 64};
floataver = 0;
intx = fun(a, 8, &aver);
printf("%d(aver:%.4f)\n",x, aver);
}
///sizeof (能求出某个变量占用的内存空间大小)
int *p;
char *q;
类型? sizeof() ?
p int *(整型指针) 4
*p int (整型) 4
q char *(字符型指针) 4
*q char (字符型) 1
int (4) char (1) 无论什么指针(4) : 原因: 因为指针存的就是地址,无论什么地址,都是4
#include <stdio.h>
int main()
{
int*p;
char*q;
printf("sizeof(*p)%d, sizeof(p) %d\n", sizeof(*p), sizeof(p));
printf("sizeof(*q)%d, sizeof(q) %d\n", sizeof(*q), sizeof(q));
}
int a[5]; a = 0x00001100
a 数组的首地址
&a[0] 第一个元素a[0] 的地址 0x0000 1100
&a[2] 第三个元素a[2] 的地址 0x0000 1108
a <=====> &a[0]
变量(全局变量、局部变量)
变量定义
int a;
float b;
char c;
变量定义规范
1) 变量尽量小写
2) 变量定义时要清晰的表达出变量的含义 (尽量不要简写, 尽量不要用拼音)
3) 命名方式有3种
StudentName 大驼峰命名法
studentName 小驼峰命名法
student_name linux风格
局部变量(定义在函数中的变量属于局部变量)
例1:
#include <stdio.h>
void fun()
{
intx; //x 是局部变量,只在fun中有效
}
int main()
{
x= 100; //此处使用x 就出错(编译器会认为 x未定义)
}
hello.c:8:2: error: ‘x’ undeclared(first use in this function)
undeclared 未定义
例2:
#include <stdio.h>
void fun()
{
intx = 100;
}
int main()
{
intx = 200; //不同函数中可以有同名变量,不冲突
printf("xis %d\n", x); // 200
}
例3:
#include <stdio.h>
void fun()
{
intx = 100; //
}
int main()
{
intx; //局部变量如果未初始化,默认值为 随机数
fun();
printf("xis %d\n", x); //??? 随机值
}
局部变量特点 : 放在函数里面的变量是局部变量
1) 两个不同函数中可以有同名局部变量
2) 局部变量只在函数中有效
3) 参数和局部变量也不能同名
4) 局部变量如果没付初值,那么值为 随机值
///全局变量(定义在函数外面的变量是全局变量,在程序的任何位置都可以访问)
例1:
#include <stdio.h>
int x = 100;
int main()
{
printf("xis %d\n", x); //(B) //A 0 B 100 C 编译失败
}
例2:
#include <stdio.h>
int x = 100;
void fun()
{
x= 200;
}
int main()
{
fun();
printf("xis %d\n", x); //(B) //A100 B 200 C 0 D 编译失败
}
例3:
#include <stdio.h>
int x = 100;
void fun()
{
intx = 200; //局部变量可以和全局变量同名
}
int main()
{
printf("xis %d\n", x); //(A) //A 100 B 200 C 0 D 编译失败
}
例4:
#include <stdio.h>
int x; //全局变量未赋初值,默认为0
void fun()
{
intx = 200;
}
int main()
{
fun();
printf("xis %d\n", x); //C A 随机数 B 200 C 0 D 编译失败
}
1) 定义在函数外面的变量是全局变量
2) 全局变量在程序的任何位置都可以使用
3) 只要有一个地方改了全局变量,其他地方也改
4) 全局变量默认值为 0
5) 全局变量不能同名,
//函数声明(作用是告诉编译器,此函数是长什么样的)
函数的定义尽量放在函数调用的前面,函数先定义再调用
例:
#include <stdio.h>
int main()
{
intx = max(3, 5);
}
int max(int a, int b)
{
returna > b ? a : b;
}
如果函数定义在函数调用的下面,函数就要先声明一下
#include <stdio.h>
int max(int a, int b); //函数声明
int main()
{
intx = max(3, 5);
}
int max(int a, int b)
{
returna > b ? a : b;
}
函数的声明:
1) void fun(); ///要注意:有" ;"
2) 函数的声明不需要函数体
3) 函数的声明一定与定义一致
4) 函数的声明尽量放在头文件中
作业
1. 写一个函数,能输出n阶杨辉三角形 (输出的阶数,通过参数传递)
2. n只猴子围坐成一个圈,
按顺时针方向从1到n编号。
然后从1号猴子开始
沿顺时针方向从1开始报数,
报到m的猴子出局,
再从刚出局猴子的下一个位置重新开始报数,
如此重复,直至剩下一个猴子
它就是大王。
设计并编写程序,实现如下功能:
(1) 要求由用户输入开始时的猴子数n(8)、
报到的数m(4)。
(2) 给出当选猴王的编号。