C语言基础day8

复习

定义函数

4部分

返回值类型 函数名(参数列表(可以为空))
{
	函数体

}

形参和实参

形参:定义在参数列表中的变量。和定义在{}里的变量只有唯一区别,形参需要被实参初始化。每个形参都要写类 型,形参之间用,隔开。

实参:调用函数时,写在()里的变量或者常量。

返回值

return 返回的值(可以是常量也可以是变量)。

一旦函数执行到return,函数马上结束。然后会把返回值给主调函数。主调函数如果使用返回值,可以将返回值赋值给某个变量,也可以无视返回值。

int fun()
{
	return 1;
}

int main()
{
    fun();//本次调用fun函数的返回值被主调函数无视了
    int a = fun();//本次调用fun函数的返回值被主调函数赋值给了变量a。
    return 0;
}

如果函数没有返回值。返回值类型写void

变量的生命周期和作用域

{}

变量的作用域在定义它的{}中。

局部变量和全局变量:

定义的变量没有被任何{}包含(也可以理解成没有被任何函数包含)是全局变量。否则就是局部变量。

初始值:全局变量如果不初始化,默认值是0。局部变量不初始化是随机值。

生命周期:全局变量在程序开始时创建,程序结束后释放;局部变量{}执行时创建,{}执行完毕释放。

作用域:全局变量整个程序都可以使用。局部变量只能在定义它的{}内使用。

重名:全局变量和局部变量在同一个作用域内都不能重名。可以在包含的小作用域中重名。

作业1:

定义函数判断一个整数是否为质数

参数:要判断的整数

返回值:0 表示不是质数  1 表示是质数

#include <stdio.h> 

//在函数调用那一行的上面,必须有该函数的定义或者声明;不然编译器可能会报错。

int isPrime(int num);//函数声明   将定义函数的第一行赋值,在后面加;

int main()
{
	int num;
	for(num = 100;num < 201;num++)
	{
		if(isPrime(num))//直接判断函数的返回值 if(isPrime(num) == 1)
		{
			printf("%d\n", num);
		}
	}
	return 0;
}

int isPrime(int num)
{
	int i;
	for(i = 2;i < num;i++)
	{
		if(num%i == 0)
		{
			return 0;//在这里已经判断出不是质数,函数可以立刻停止
		}
	}
	//只要循环能走完,必然是质数
	return 1;
}

作业2:

定义函数求任意整数的位数

例如:12345

返回:5

参数:要计算整数

返回值:整数的位数

#include <stdio.h> 

//在函数调用那一行的上面,必须有该函数的定义或者声明;不然编译器可能会报错。

int numBits(int num);

int main()
{
	printf("%d\n", numBits(12345));//直接打印函数返回值
	return 0;
}

int numBits(int num)
{
	int count = 0;
	while(num != 0)
	{
		num /= 10;
		count++;
	}
	return count;
}

作业3:

35选7使用函数封装。

#include <stdio.h> 
#include <stdlib.h>

int results[7] = {0};
int userNums[7] = {0};
int isResutltExists(int num, int index);
/*
初始化结果数组 随机7个不重复的数放到数组results里
*/
void initResutlts()
{
    int i;
    //1 生成7个随机数
	for(i = 0;i < 7;i++)
	{
        do
        {
            results[i] = rand()%35+1;//随机一个数
        }while(isResutltExists(results[i], i));		
	}
}
/*
判断一个整数是否已经在results数组中存在
参数1:要判断的数
参数2:这个数在数组中的位置
返回值:1 存在  0 不存在
*/
int isResutltExists(int num, int index)
{
    int j;
    for(j = 0;j < index;j++)
    {
        if(results[j] == num)
        {           
            return 1;//只要找到重复的,函数马上结束
        }
    }
    return 0;
}

int isIn1to35(int num);
int isUsernumExists(int num, int index);
/*
用户输入函数 用户输入7个1~35之间不重复的数,存在userNums数组中
*/
void userInput()
{
    int i;
    for(i = 0;i < 7;i++)
	{
        //输入的数不在1~35之内或者 有重复都循环
        do
        {
            scanf("%d", &userNums[i]);
        }while(isIn1to35(userNums[i])==0 || isUsernumExists(userNums[i], i)==1);			
	}  
}

/*
判断整数是否在1~35之间
参数:要判断的整数
返回值:0 不在  1 在
*/
int isIn1to35(int num)
{
    if(num<1 || num>35)
    {
        printf("超出了1~35的范围\n");
        return 0;
    }
    else
    {
        return 1;
    }
}

/*
判断用户输入的数在 userNum数组中是否有重复
参数1:要判断的数
参数2:这个数在数组中的位置
返回值:1 存在  0 不存在
*/
int isUsernumExists(int num, int index)
{
    int j;
    for(j = 0;j < index;j++)
    {
        if(userNums[j] == num)
        {           
            return 1;//只要找到重复的,函数马上结束
        }
    }
    return 0;
}

/*
查找userNum和Results数组中重复数字的个数
返回值:相同数字的个数
*/
int sameInUsernumsAndResults()
{
    int i, j;
    int count = 0;
	for(i = 0;i < 7;i++)
	{
		int j;
		for(j = 0;j < 7;j++)
		{
			if(results[i] == userNums[j])
			{
				count++;
				break;
			}
		}
	}
    return count;
}

/*
根据相同数字的个数计算开奖结果
*/
void showResult(int count)
{
    switch(count)
	{
	case 7:
		printf("1000 0000\n");
		break;
	case 6:
		printf("10000\n");
		break;
	case 5:
		printf("100\n");
		break;
	case 4:
		printf("2\n");
		break;
	default:
		printf("谢谢参与\n");
	}
}

/*
显示两个数组中的元素
*/
void showArrs()
{
    int i;
    for(i = 0;i < 7;i++)
	{
		printf("%d %d\n", results[i], userNums[i]);
	}
}

int main()
{
    srand(time(0));
    initResutlts();//生成随机数
    userInput();//用户输入
    int count = sameInUsernumsAndResults();//获得相同数字的个数
    showResult(count);//显示开奖结果
    showArrs();//显示数组信息
    return 0;
}

1、指针变量

指针变量的本质是变量,变量用来存放数据,描述逻辑。

1. 什么是指针变量

指针变量是存放地址的变量。

变量的运算,是对变量中存放数据的运算。

int a;
printf("%d\n", a+1);//不知道结果是多少,因为变量里没有值。

2. 地址的运算

地址只有两种运算:

1、地址偏移 + -

int a;
printf("%p %p\n", &a, &a+1);

在这里插入图片描述

int 类型地址+1 是+4字节

char a;
printf("%p %p\n", &a, &a+1);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4SwRrQL7-1645663339139)(C:\Users\mudonghai\Desktop\C基础\day8\image-20220113105935218.png)]
char类型地址+1 是+1字节

地址偏移一个单位,偏移的字节数是地址类型的大小。

2、间接运算 * 间接运算是一元运算(只有一个操作数) 乘法是二元运算(有两个操作数)

*在操作数的左边。

间接运算可以通过地址访问地址对应的变量。

间接运算的到的结果不是一个数值,得到的是地址对应的变量的本身。间接运算的结果是一个变量。

#include <stdio.h>

int main()
{
	int a;
	*(&a) = 10;//因为*(&a)运算得到变量a  所以把10赋值给了a
	printf("%d\n", a);
	return 0;
}

3. 定义指针变量

任何符号出现在声明的语句中,都不是运算符。声明是:解释标识符的身份。出现了新的标识符,就是声明语句。

int *p;//定义变量p,*说明p是指针变量,既然是指针变量,就要存放地址,所以我们还要告诉编译器p是存放什么类型地址的指针变量。int类型。

指针的声明属于复杂声明,一步定义不完,就是复杂声明。

这里的*是说明p是指针变量身份的符号,它不是运算符!!!

能够在声明的语句中表达标识符身份的符号,一共有三个!

*指针变量

[] 数组

() 函数

指针变量的名字可以随意命名(符合语法的前提下)。因为指针变量的英文名point,所以我们经常给指针变量命名p。

1. 初始化

​ int a;

​ int *p = &a;//这里的是给p初始化,因为这里的*不是运算符。

2. 赋值

​ int a;

​ int *p;

​ p = &a;//当指针变量p中存放a的地址,我们说:p指向a。

下面的示例毫无意义,仅仅是为了演示语法。

#include <stdio.h>

int main()
{
	int a;
	int* p = &a;//*是表达p是指针变量身份的符号
	*p = 10;//*是间接运算符,*p等价于*(&a) 得到的结果是变量a本身
	printf("%d\n", a);
	return 0;
}

4.输出指针变量

%p %x

5.指针变量的意义

示例1:

在被调函数中使用主调函数中的变量,通过地址传递。

void putNum(int* num)//定义指针变量形参
{
	*num = 10;//因为num指向main中的a,所以*num得到变量a,所以这里是给main中的变量a赋值
}

int main()
{
	int a;
	putNum(&a);//使用变量a的地址,对putNum函数的形参num初始化
	printf("%d\n", a);
	return 0;
}

练习1:

分别定义 int float 的变量,通过指针赋值,并输出变量的值和指针变量的值(地址)。 (熟悉指针)

#include <stdio.h>

int main()
{
	int a;
	float b;
	int* pa;
	float* pb;
	pa = &a;//给指针变量赋值
	pb = &b;
	*pa = 10;//pa指向a,所以*p得到a 
	*pb = 10.2;
	printf("%d  %f\n", a, b);
	printf("%p  %p\n", pa, pb);
	return 0;
}

练习2:

定义函数,通过指针变量实现两个整数的交换。

在被调函数中交换主调函数中的两个变量的值。

#include <stdio.h>

void swap(int* num1, int* num2)
{
	int t = *num1;//*num1运算的结果是变量a本身
	*num1 = *num2;//*num2运算的结果是变量b本身
	*num2 = t;
    /*
    int t = a;
    a = b;
    b = t;
    */
}

int main()
{
	int a = 10, b = 20;//变量一旦被创建,变量的地址就不能改变
	swap(&a, &b);//调用函数时,用&a初始化num1,&b初始化num2,于是我们说num1指向a,num2指向b
	printf("%d %d\n", a, b);
	return 0;
}

2、指针与数组

1) 数组名就是数组的首地址(第一个元素的地址)。数组名字是地址常量。

2) 数组中的元素在内存中连续存放。

int main()
{
    int a[10];//a是数组名,是数组的首元素地址,也就是a[0]的地址 ,a等价于&a[0],a是常量
	int i;
	for(i = 0;i < 10;i++)
	{
		printf("%p\n", &a[i]);
	}
	return 0;
}

运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XqS28h86-1645663339140)(C:\Users\mudonghai\Desktop\C基础\day8\image-20220113144735371.png)]
因为int类型的元素,占4个字节,所以每个元素之间相差4个字节。

正好符合地址偏移的规律。

示例2:

#include <stdio.h> 

int main( )
{
	int a[10] = {12,23,34,45,56,67,78,9,98,33};
	int *p; 
	p = a;//给指针变量p赋值,因为a是数组名,是数组首元素地址,所以不需要对a取地址
    //数组名是数组元素类型的地址。
    //当指针变量p存放数组a的首地址时,我们说指针变量p指向数组a。
	int i; 
	for(i=0; i<10; i++)
	{
		//printf("%d", *(p+i)); //当i=0时,p+i指向a[0],当i=1时,p+i指向a[1]
		printf("%d", p[i]);  //p[i]等价于*(p+i)   a[i] 可以写成 *(a+i)
	}
	return 0;
}

练习3:

使用指针表达每个元素的值,将数组元素求和。输出最终结果。

#include <stdio.h>

int main()
{
	int a[10] = {1,2,3,4,5,6,7,8,9,0};
	int* p = a;//定义指针变量p指向数组a
	int i;
	int sum = 0;
	for(i = 0;i < 10;i++)
	{
		//使用指针遍历数组,和使用数组名遍历数组是一样的,因为指针的运算就是地址的运算,数组名就是地址
		sum += p[i]; 
	}
	printf("%d\n", sum);
	return 0;
}

练习4:

定义字符数组,将字符串放在数组中,定义指针指向数组,并输出数组中保存的内容。

printf(“%s\n”,字符串首地址);

C语言对字符串的处理有两个要素:

  1. 字符串首地址 作为字符串的开始

  2. ‘\0’作为字符串的结尾

    int main()
    {	
        char buf[] = "hello world";	//定义字符数组buf,用字符串常量"hello world"初始化这个数组,默认初始化,数组长度为12,因为得给'\0'留空间
        char* p = buf;//定义字符类型指针指向字符类型数组buf	
        //%s 需要字符串两个要素,首地址  '\0'  %s从我们给的地址开始一个字节一个字节算,算到'\0'结束
        printf("%s\n", p+5);//输出数组中存放的字符串	从空格开始输出	
        printf("%s\n", buf);//输出数组中存放的字符串	
        return 0;
    }
    

示例3:

数组作为函数的参数,一般传递两个参数

1 数组的首地址

2 数组的长度

#include <stdio.h>
/*打印任意整型数组
参数1:是指针变量,存放数组的首地址
参数2:存放数组长度
*/
void print_array(int *p, int n) 
{
	int i; 
	for(i=0; i<n; i++)
	{
		printf("%d, ", p[i]);//p[i]通过指针变量遍历数组
	}
}

int main()
{
	int a[6] = {1,2,3,4,5,6};
	int b[8] = {6,6,6,6,6,6,6,6};
	print_array(a,6);//使用a初始化p,p遍历数组a
	print_array(b,8);//使用b初始化p,p遍历数组b
	return 0;
}

练习5:

编写函数,实现功能: 对数组求和,并返回给主调函数。

将主调函数中的数组传给被调函数。

#include <stdio.h>

int arrSum(int* arr, int len)
{
	int sum = 0;
	int i;
	for(i = 0;i < len;i++)
	{
		sum += arr[i];
	}
	return sum;
}

int main()
{
	int a[10] = {1,2,3,4,5,6,7,8,9,0};
	int sum = arrSum(a, 10);
	printf("%d\n", sum);
	return 0;
}

练习6:

编写函数,实现对任意整型数组的升序排序。

#include <stdio.h>

void sort(int* arr, int len)
{
	int i, j;
	for(i = 0;i < len-1;i++)//外层循环反复冒泡
	{
		for(j = 0;j < len-1-i;j++)//内层循环冒一个泡
		{
			if(arr[j] > arr[j+1])
			{
				int t = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = t;
			}
		}
	}
}

int main()
{
	int a[10] = {12,2,31,14,25,86,17,8,92,20};
	sort(a, 10);
	int i;
	for(i = 0;i < 10;i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
	return 0;
}

作业1:

编写函数fun:从n个学生的成绩中统计出低于平均分的学生人数,

由返回值返回,平均分存放在形参 ptr_aver 所指的存储单元中(即平均分由参数返回)。

函数最终会有两个结果,人数通过返回值给主调函数,平均分通过形参里的指针变量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)。

作业2:

编写一个函数,将数组中n个数按反顺序存放

假设主调函数中有数组int a[8] = {3,4,5,6,7,9,9,2};

执行完被调函数,数组变成2 9 9 7 6 5 4 3

作业3:

编写函数,实现字符串追加 功能。但不能调用字符串函数;

char s1[20] = “hello ”;

char s2[] = “world”;

调用函数后,将world放到s1数组的”hello ”后面

知识点:当数组存放字符串时,作为函数的参数只需要传递首地址,因为字符串有’\0’作为结尾。

实现strcat的功能,但是不能调用strcat
t;
}
}
}
}

int main()
{
int a[10] = {12,2,31,14,25,86,17,8,92,20};
sort(a, 10);
int i;
for(i = 0;i < 10;i++)
{
printf("%d “, a[i]);
}
printf(”\n");
return 0;
}


 

 

 

 

 

 



## **作业1:** 

编写函数fun:从n个学生的成绩中统计出低于平均分的学生人数,

由返回值返回,平均分存放在形参 ptr_aver 所指的存储单元中(即平均分由参数返回)。

 

函数最终会有两个结果,人数通过返回值给主调函数,平均分通过形参里的指针变量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)。

 

## **作业2:** 

 编写一个函数,将数组中n个数按反顺序存放

假设主调函数中有数组int a[8] = {3,4,5,6,7,9,9,2};

执行完被调函数,数组变成2 9 9 7 6 5 4 3 

 

## **作业3:**

编写函数,实现字符串追加 功能。但不能调用字符串函数;

char s1[20] = “hello ”;

char s2[] = “world”;

调用函数后,将world放到s1数组的”hello ”后面

知识点:当数组存放字符串时,作为函数的参数只需要传递首地址,因为字符串有’\0’作为结尾。



实现strcat的功能,但是不能调用strcat
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

encounter♌

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

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

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

打赏作者

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

抵扣说明:

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

余额充值