是否是质数?
#include <stdio.h>
#include <stdbool.h>
bool is_prime(int num);
int main() {
int num;
printf("请输入一个整数:");
scanf("%d", &num);
if (is_prime(num)) {
printf("%d是质数。\n", num);
} else {
printf("%d不是质数。\n", num);
}
return 0;
}
bool is_prime(int num) {
if (num < 2) {
return false;
}
for (int i = 2; i * i <= num; i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
矩阵的乘法
#include <stdio.h>
#define MAX_ROW 4
#define MAX_COL 5
int main()
{
int a[MAX_ROW][3], b[3][MAX_COL], c[MAX_ROW][MAX_COL];
// 输入矩阵A和B的数据
printf("请输入矩阵A的数据:\n");
for (int i = 0; i < MAX_ROW; i++) {
for (int j = 0; j < 3; j++) {
scanf("%d", &a[i][j]);
}
}
printf("请输入矩阵B的数据:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < MAX_COL; j++) {
scanf("%d", &b[i][j]);
}
}
// 计算矩阵C的值
for (int i = 0; i < MAX_ROW; i++) {
for (int j = 0; j < MAX_COL; j++) {
c[i][j] = 0;
for (int k = 0; k < 3; k++) {
c[i][j] += a[i][k] * b[k][j];
}
}
}
// 输出矩阵C的值
printf("\n矩阵C的值为:\n");
for (int i = 0; i < MAX_ROW; i++) {
for (int j = 0; j < MAX_COL; j++) {
printf("%d ", c[i][j]);
}
printf("\n");
}
return 0;
}
在这个示例代码中,我们首先定义了三个矩阵a、b和c,其中a和b分别为4行3列和3行5列的矩阵,c为4行5列的矩阵。用户可以通过标准输入输入矩阵a和b的数据,然后程序计算出矩阵c的值,并输出到屏幕上。
矩阵乘法的核心代码在于第三重循环中的计算方法,即对于矩阵C中的每一个元素c[i][j],都需要将矩阵A中第i行的元素和矩阵B中第j列的元素逐一相乘,并将它们的积累加起来,最终得到c[i][j]的值。
回形矩阵
#include <stdio.h>
#define MAX_N 10
int main()
{
int n;
int a[MAX_N][MAX_N];
int num = 1; // 当前要填充的数值,从1开始
// 输入n的值
printf("请输入n的值:");
scanf("%d", &n);
// 初始化矩阵a
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
a[i][j] = 0; // 初始值设为0
}
}
// 回形遍历方阵,并填充数值
int row = 0, col = 0; // 当前位置的行和列
while (num <= n * n) { // 循环条件:还有未填充的数值
// 第一步:向右走到尽头(直到达到边界或者遇到已经填充的数值)
while (col < n && a[row][col] == 0) {
a[row][col++] = num++; // 填充当前位置并将列坐标加1
}
col--; // 因为最后一次填充时超出了边界,所以需要将列坐标减回来
row++; // 将行坐标加1,准备向下走
// 第二步:向下走到尽头(同样需要判断边界和已填充数值)
while (row < n && a[row][col] == 0) {
a[row++][col] = num++; // 填充当前位置并将行坐标加1
}
row--; // 同理,需要将行坐标减回来
col--; // 将列坐标减1,准备向左走
// 第三步:向左走到尽头
while (col >= 0 && a[row][col] == 0) {
a[row][col--] = num++; // 填充当前位置并将列坐标减1
}
col++; // 将列坐标加1,准备向上走
row--; // 将行坐标减1,准备向上走
// 第四步:向上走到尽头
while (row >= 0 && a[row][col] == 0) {
a[row--][col] = num++; // 填充当前位置并将行坐标减1
}
row++; // 将行坐标加1,准备向右走
col++; // 将列坐标加1,准备向右走
}
// 输出结果
printf("\n回形遍历方阵结果为:\n");
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
printf("%3d ", a[i][j]);
}
printf("\n");
}
return 0;
}
在这个示例代码中,我们首先接收用户输入的n值,并初始化一个n*n的矩阵a。然后我们使用四个while循环依次完成“右下左上”的遍历过程,并将递增的num值填充到矩阵a中。最后我们输出矩阵a的结果到屏幕上。
需要注意的一点是,在每次while循环结束后,row和col的值都需要调整回上一个合法的位置,以便进行下一次循环。
为什么说scanf和gets是不安全的,而fgets是安全的?
scanf 和 gets 函数被认为是不安全的,因为它们无法处理输入数据的长度和内容,容易导致缓冲区溢出和安全漏洞。相反,fgets 函数被认为是安全的,因为它可以指定读取的最大字符数,并且只会读取指定数量的字符,从而避免了缓冲区溢出。
具体来说,scanf 和 gets 函数存在以下问题:
- scanf 函数无法限制输入数据的长度,因此很容易导致缓冲区溢出。例如,如果使用 %s 格式化符读取一个超过目标缓冲区大小的字符串,则会导致缓冲区溢出。
- gets 函数同样无法限制输入数据的长度,它会一直读取数据,直到读取到换行符或者达到缓冲区的末尾。这种行为容易导致缓冲区溢出,因为恶意用户可以通过输入长字符串来覆盖缓冲区之外的内存。
相比之下,fgets 函数有如下优点:
- fgets 可以指定读取的最大字符数,这可以帮助我们控制输入数据的长度,避免缓冲区溢出。
- fgets 一次只能读取指定数量的字符,它会在读取到给定数量的字符、读取到换行符或到达缓冲区末尾时停止读取,因此可以避免恶意用户输入超长字符串,从而防止缓冲区溢出和安全漏洞。
综上所述,scanf 和 gets 函数存在安全问题,应该尽量避免使用,而 fgets 函数则是一种更安全可靠的选择。