写在前面:
昨天有事休息了一天,今天给大家补上,今天着重说一下循环结构、循环控制以及数组。话不多说开启今日的C语言基础。
目录
1.循环结构
for语句
一般形式
for(expression1;expression2;expression3)
{statements}
执行过程
- 先求解表达式1;
- 求解表达式2,若为真,则执行循环体,然后执行步骤3;若为假,则执行步骤5;
- 求解表达式3;
- 转回执行步骤2;
- 执行for下面的语句
for语句构成循环
如:
for(i = 1;i <= 100;i++)
{
sun = sum + i;
}
for语句构成循环
- 表达式1可省略,单循环之前应给循环变量赋值
- 表达式2可省略,但将陷入死循环
- 表达式3可省略,但在循环体中增加使循环变量值改变的语句
首先看一下下面这个程序
// 外层循环,控制变量i从0到5
for(int i=0; i<6; i++)
{
// 内层循环,控制变量j从0到2
for(int j=0; j<3; j++)
{
// 打印当前的i和j的值
printf("i:%d j:%d
", i, j);
}
}
这是一个C语言程序,它使用了两个嵌套的for循环来打印出一系列的i和j的值。外层循环控制变量i从0到5,内层循环控制变量j从0到2。每次内层循环结束后,外层循环的i值会增加1,然后内层循环重新开始。在内层循环中,程序使用printf函数打印出当前的i和j的值。
外层循环执行一次,内层循环执行一轮。
可以根据这个来输出一个九九乘法表:
思路:
1.使用两层嵌套循环来实现九九乘法表的输出。
2.外层循环控制行数,从1到9,每次循环递增1。
3.内层循环控制列数,从1到当前行数i,每次循环递增1。
4.在内层循环中,使用printf函数打印乘法表的每个元素,格式为:j * i = 结果。
5.每行结束后,使用printf函数输出一个换行符,以便在下一行开始新的一行。
#include <stdio.h>
int main() {
// 外层循环控制行数,从1到9
for (int i = 1; i <= 9; i++) {
// 内层循环控制列数,从1到i
for (int j = 1; j <= i; j++) {
// 打印乘法表的每个元素,格式为:j * i = 结果
printf("%d*%d=%d\t", j, i, j * i);
}
// 每行结束后换行
printf("
");
}
return 0;
}
练习
/*
以下程序执行后的输出结果是()
A.自然数1~9的累加和
B.自然数1~10的累加和
C.自然数1~9中的奇数和
D.自然数1~10中的偶数和
*/
int i,s = 0;
for(i = 1;i < 10;i += 2)
{
s += i + 1;
}
printf("%d\n",s);
这段代码是一个C语言程序,用于计算一个累加和。让我们逐步分析代码的逻辑:
- 定义变量
i
和s
,其中s
初始化为0,用于存储累加和。- 使用
for
循环,循环变量i
从1开始,到9结束(因为i < 10
),每次循环i
增加2(i += 2
)。这意味着循环只会遍历奇数(1, 3, 5, 7, 9)。- 在循环体中,执行
s += i + 1;
,这实际上是将i + 1
的值加到s
上。- 最后,使用
printf
函数打印变量s
的值。现在,我们可以计算累加和的具体值:
- 当
i = 1
时,s += 1 + 1
,即s = 0 + 2
。- 当
i = 3
时,s += 3 + 1
,即s = 2 + 4
。- 当
i = 5
时,s += 5 + 1
,即s = 6 + 6
。- 当
i = 7
时,s += 7 + 1
,即s = 12 + 8
。- 当
i = 9
时,s += 9 + 1
,即s = 20 + 10
。最终,
s = 30
。因此,程序的输出结果是30,这是自然数1到9中所有奇数加1后的和。所以正确答案是:D
下面再进行一个练习:
终端输入行数,实现以下功能:
输入5
*
**
***
****
*****
我们来分析一下:
首先,我们需要从终端获取用户输入的行数,它的格式可以理解为
1 1
2 2
3 3
然后,我们需要使用嵌套循环来实现打印星号的功能。外层循环控制行数,内层循环控制每行的星号数量。并且在内层循环中,我们需要打印相应数量的星号,并在每行星号后换行。
代码如下:
#include <stdio.h>
int main() {
int n, i, j;
// 从终端获取用户输入的行数
printf("请输入行数:");
scanf("%d", &n);
// 使用嵌套循环打印星号
for (i = 1; i <= n; i++) { // 外层循环控制行数
for (j = 1; j <= i; j++) { // 内层循环控制每行的星号数量
printf("*");
}
printf("
"); // 每行星号后换行
}
return 0;
}
首先,程序包含了头文件
stdio.h
,这是因为我们需要使用标准输入输出函数(如printf
和scanf
)。
main()
函数是程序的入口点。在C语言中,每个程序必须有一个名为main
的函数作为程序执行的起点。在
main()
函数内部,我们声明了三个整型变量n
,i
,j
。其中n
用于存储用户输入的行数,i
和j
分别用作循环计数器。接下来,程序通过
printf
函数提示用户输入行数,并使用scanf
函数读取用户的输入并将其存储到变量n
中。然后,程序使用两个嵌套的
for
循环来实现打印星号的功能。外层循环控制行数,内层循环控制每行的星号数量。在内层循环中,程序使用
printf
函数打印一个星号,然后继续下一次迭代。当内层循环结束时,即一行的星号打印完毕,程序使用printf(" ")
换行,以便开始打印下一行。最后,程序返回0,表示程序正常结束。
总结起来,这个程序的主要功能是根据用户输入的行数,打印出相应数量的星号,每行星号的数量逐行递增。
进阶以下:
终端输入行数,实现以下功能:
输入5
*
**
***
****
*****
*****
****
***
**
*
分析一下:
其格式我们可以由上面的程序延伸一下
行数 空格 *
1 0 5
2 1 4
3 2 3
4 3 2
5 4 1
解题思路:
1.首先,我们需要从终端获取用户输入的行数。
2.然后,我们使用两个嵌套的
for
循环来实现打印星号的功能。第一个循环用于打印上 半部分的星号图案,第二个循环用于打印下半部分的星号图案。3.在第一个循环中,外层循环控制行数,内层循环控制每行的星号数量。每次迭代时, 我们打印一个星号,并在每行星号后换行。
4.在第二个循环中,外层循环同样控制行数,但这次是从n-1开始递减到1。内层循环则 控制每行的星号数量,从1开始递增到i。这样可以实现下半部分的对称性。
5.最后,程序返回0,表示程序正常结束。
代码如下:
#include <stdio.h>
int main() {
int n, i, j;
// 从终端获取用户输入的行数
printf("请输入行数:");
scanf("%d", &n);
// 打印上半部分星号图案
for (i = 1; i <= n; i++) { // 外层循环控制行数
for (j = 1; j <= i; j++) { // 内层循环控制每行的星号数量
printf("*");
}
printf("
"); // 每行星号后换行
}
// 打印下半部分星号图案
for (i = n - 1; i >= 1; i--) { // 外层循环控制行数,从n-1开始递减到1
for (j = 1; j <= i; j++) { // 内层循环控制每行的星号数量,从1开始递增到i
printf("*");
}
printf("
"); // 每行星号后换行
}
return 0;
}
while语句
while语句构成循环
基本形式
while(表达式)
{
statatments;
}
例:求1到10的和
1.先获取10个数2.把10个数累加
int i=1,sum=0;
while(i<=10)
{
sum+=i;
i++;
}
printf("%d\n",sum);
do_while语句
do_while语句构成循环
基本形式
do
{
statatments;
}while(表达式);
注:while和do_while的区别
while先判断在执行
do_while先执行一次,在判断
死循环:while(1);for(;;);
2. 循环控制
break语句
用于从循环体内跳出循环体,即提前结束循环
- break只能用在循环语句和switch语句中
for(r = 1;r <= 10;r++)
{
area = pi * r * r;
if(area > 100) break;
printf("%f",area);
}
素数
在一个大于1的自然数中,除了1和此整数自身外,没法被其他自然数整除的数。
换句话说,只有两个正因数(1和自己)的自然数即为素数。比1打但不是素数的数成为合数。1和0既非素数也非合数。
例:
对一个大于或等于3的正整数,判断它是不是一个素数
- S1:输入整数n的值
- S2:i=2
- S3:n被i除,得余数r
- S4:如果r=0,则打印n“不是素数”,算法结束;否则执行S5
- S5:i+1→i
- S6:如果i<=根号n,返回S3;否则打印n“是素数”;然后算法结束
程序如下:
#include <stdio.h>
#include <math.h>
int main()
{
int n, i; // 定义整数变量n和i
double sqrt_n; // 定义浮点数变量sqrt_n,用于存储n的平方根
printf("请输入一个大于或等于3的正整数:"); // 提示用户输入一个大于或等于3的正整数
scanf("%d", &n); // 读取用户输入的整数并赋值给n
if (n < 3)
{ // 如果输入的数字小于3,则输出错误信息并退出程序
printf("输入的数字必须大于或等于3。\n");
return 1;
}
i = 2; // 初始化i为2,因为从2开始检查是否为素数
sqrt_n = sqrt(n); // 计算n的平方根并赋值给sqrt_n
while (i <= sqrt_n)
{ // 当i小于等于n的平方根时,执行循环
if (n % i == 0)
{ // 如果n能被i整除,说明n不是素数
printf("%d不是素数。\n", n); // 输出n不是素数的信息
return 0; // 结束程序
}
i++; // i递增,继续检查下一个可能的因子
}
printf("%d是素数。\n", n); // 如果循环结束后没有找到任何因子,说明n是素数,输出n是素数的信息
return 0; // 程序正常结束
}
这个程序的主要目的是判断一个大于或等于3的正整数是否为素数。以下是程序的思路:
- 首先,程序提示用户输入一个大于或等于3的正整数,并将其存储在变量n中。
- 如果输入的数字小于3,则输出错误信息并退出程序。
- 初始化变量i为2,因为从2开始检查是否为素数。同时计算n的平方根并存储在sqrt_n中。
- 进入循环,当i小于等于n的平方根时执行以下步骤:
- 如果n能被i整除(即余数为0),说明n不是素数,输出n不是素数的信息并结束程序。
- 如果n不能被i整除,将i递增1,继续检查下一个可能的因子。
- 如果循环结束后没有找到任何因子,说明n是素数,输出n是素数的信息。
- 程序正常结束。
通过以上思路,程序可以有效地判断一个给定的正整数是否为素数。
3.数组
- 构造数据类型之一
- 数组是具有一定顺序关系的若干个变量的集合,组成数组的各个变量成为数组的元素
- 数组中各元素的数据类型要求相同,用数组名和下表确定。数组可以是一维的,也可以是多维的。
由一个或多个相同类型数据组成的集合特点:
数据类型相同
内存连续
3.1一维数组
一维数组的定义
- 所谓一维数组是指只有一个下标的数组。它在计算机的内存中是连续存储的。
格式:存储类型 数据类型 数组名[元素个数]
int arr[5];
定义了一个int 类型的数组,可以存储5个int类型的数据
例: 只有在定义时,5表示元素个数,其他任何情况下5表示数组的第6个元素
例:
int a[5]={5,6,7,8,9};printf("%d %d %d\n",a[0],a[2],a[4]);
访问元素: 索引从0开始
a[0]----->5
a[1]----->6
a[2]----->7
a[3]----->8
a[4]----->9
注意:
- C语言对数组不做越界检查,使用时要注意
- int a[5]; a[5]=10
- 关于用变量定义数组维数
- int i = 15; int a[i]
3.2数组名
也表示数组的首地址,是地址常量,不能为左值(=左边)
3.3一维数组的引用
- 数组必须先定义,后使用
- 只能逐个引用数组元素,不能一次引用整个数组
- 数组元素表示形式:数组名[下标]
- 其中:下标可以是常量或整形表达式
例 int a[10];
printf(“%d”, a); (×)
for(j=0;j<10;j++)
printf(“%d\t”, a[j]); (√)
3.4数组的初始化
- 初始化方式:在定义数组时,为数组元素赋初值
- int a[5]={1,2,3,4,5};
- 说明
- 数组不初始化,其元素值为随机数
- 对static数组元素不赋初值,系统会自动赋以0值
- 只给部分数组元素赋初值
static int a[5];
等价于:a[0]=0; a[1]=0; a[2]=0; a[3]=0; a[4]=0;
int a[5]={6,2,3};
等价于:a[0]=6; a[1]=2;a[2]=3; a[3]=0; a[4]=0;
int a[3]={6,2,3,5,1}; (×)
int a[]={1,2,3,4,5,6};//编译系统根据初值个数确定数组维数
3.4.1全部初始化
int a[5]={5,6,7,8,9}
3.4.2部分初始化
int a[5]={8,9};
未初始化部分值为0
3.4.3未初始化
int a[5];
值为随机值
定义数组元素值都为0:
int a[40]={0};
int a[40]={ };
3.5数组遍历
C语言数组遍历是指通过循环结构逐个访问数组中的元素。在C语言中,数组是一种数据结构,用于存储相同类型的多个元素。数组的遍历可以通过下标来访问每个元素。
3.5.1声明数组
在C语言中,可以使用以下语法声明一个数组:
dataType arrayName[arraySize];
其中,dataType
是数组元素的类型,arrayName
是数组的名称,arraySize
是数组的大小(即元素个数)。
3.5.2数组遍历
使用循环结构遍历数组中的每个元素。常见的遍历方式有for循环和while循环。以下是两种遍历方法的示例:
- for循环遍历数组
for (int i = 0; i < size; i++)
{
printf("%d ", numbers[i]);
}
- while循环遍历数组
int i = 0;
while (i < size)
{
printf("%d ", numbers[i]);
i++;
}
4.内存分配
- 在C语言中,内存分配是指在程序运行时为变量、数组、结构体等数据对象分配内存空间。C语言提供了多种内存分配方式,包括静态内存分配、栈上分配和堆上分配。
1.静态内存分配:在编译时进行,用于全局变量、静态变量和常量。这些变量的内存空间在程序运行期间保持固定大小,并且在程序的整个生命周期内都存在。例如:
int globalVar; // 全局变量,静态内存分配
static int staticVar; // 静态变量,静态内存分配
const int constantVar = 10; // 常量,静态内存分配
2.栈上分配:在函数调用时进行,用于局部变量、函数参数和返回地址。栈上分配的内存空间在函数调用结束后自动释放。例如:
void exampleFunction()
{
int localVar; // 局部变量,栈上分配
// ...函数体...
}
3.堆上分配:在程序运行时进行,用于动态分配的内存空间。堆上分配的内存空间需要手动管理,包括申请、使用和释放。C语言提供了以下几种堆上内存分配的函数:
malloc
:用于分配指定字节数的内存空间,并返回一个指向该内存空间的指针。如果分配失败,返回NULL。
int *ptr = (int*) malloc(sizeof(int) * arraySize); // 分配整数数组的内存空间
calloc
:与malloc
类似,但还会将分配的内存空间初始化为0。
int *ptr = (int*) calloc(arraySize, sizeof(int)); // 分配并初始化整数数组的内存空间
realloc
:用于调整已分配内存空间的大小。可以增加或减少内存空间,并可能改变内存空间的位置。
ptr = (int*) realloc(ptr, sizeof(int) * newArraySize); // 调整整数数组的内存空间大小
free
:用于释放已分配的内存空间,将其归还给操作系统。
free(ptr); // 释放整数数组的内存空间
在使用堆上分配的内存空间时,需要注意以下几点:
- 确保正确计算所需的字节数,以避免分配过小或过大的内存空间。
- 在使用分配的内存空间之前,确保检查指针是否为NULL,以避免空指针错误。
- 及时释放不再使用的内存空间,以避免内存泄漏。
总之,C语言中的内存分配是一个重要的概念,需要根据具体需求选择合适的内存分配方式,并合理管理内存资源。
5.数组大小
在C语言中,数组的大小是指数组所能容纳的元素个数。数组的大小由声明时指定的元素个数决定,并且一旦声明后,其大小就固定不变。
要确定一个数组的大小,可以使用以下方法:
1.使用sizeof
运算符:sizeof
运算符可以返回一个对象或类型所占用的字节数。对于数组来说,它返回整个数组所占用的字节数。通过将数组的总字节数除以单个元素的字节数,可以得到数组的大小。例如:
int numbers[] = {1, 2, 3, 4, 5};
int size = sizeof(numbers) / sizeof(numbers[0]); // 计算数组大小
printf("The size of the array is: %d\n", size);
2.直接查看声明时的数组大小:如果在声明数组时指定了数组的大小,可以直接从声明语句中获取数组的大小。例如:
int numbers[5]; // 声明了一个大小为5的整数数组
int size = sizeof(numbers) / sizeof(numbers[0]); // 计算数组大小
printf("The size of the array is: %d\n", size);
需要注意的是,数组的大小是固定的,不能在运行时改变。如果需要动态调整数组的大小,可以考虑使用动态内存分配函数(如malloc
和realloc
)来创建和重新分配内存空间。
留一下提供大家练习的题目,详情解释会放在Day05
1.输入任意两个数,输出两数之间(包括这两个数)偶数之和。
思路:将输入的两个数a,b中小的数a,依次加1,加到b的值,每次循环判断这个数a是否为偶数,是则累加到sum中
2.循环输入一个5位数,判断它是不是回文数。当输入0时循环结束。即12321是回文数,个位与万位相同,十位与千位相同。
3.一同学上课违纪看视频,罚他表演才艺,现场抽取10名学生现场打分赋值在数组中,为了 公平起见,去掉其中最高分和最低分,求最终平均值。