3.11笔记3

本文围绕C语言展开,探讨了break与continue语句区别、素数判断与生成算法,分析了数组和链表的性能特点,介绍了局部与外部变量的作用域及存储期限,还涉及指针、矩阵乘法等知识,给出了约瑟夫环等问题的解法及相关代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

3.11知识点3

1. break 语句和 continue 语句有什么区别?

break语句和continue语句都是控制流语句,用于改变循环的执行顺序,但它们有不同的作用:

  1. break语句用于立即退出循环,无论循环条件是否满足。当程序执行到break语句时,循环会立即终止,并且程序将继续执行循环后面的代码。break语句通常用于在达到某个条件时提前结束循环。

  2. continue语句用于跳过当前循环中剩余的代码,立即进入下一次循环的迭代。当程序执行到continue语句时,会立即停止本次循环的执行,并开始下一次循环。continue语句通常用于在某些特定条件下跳过本次循环的执行。

2. 使用 goto 计算 1-2+3-4+…+99-100 的值。

int main(void) {
   
	int sum = 0, i = 1;
loop:
	if (i & 0x1) {
   
		sum += i;
	} else {
   
		sum -= i;
	}
	i++;
	if (i <= 100) {
   
		goto loop;
	}
	printf("sum = %d\n", sum);

	return 0;
}

3. 输入一个整数,判断这个数是不是素数。

bool is_prime(int n) {
	for (int i = 2; i * i < n; i++) {
		if (n % i == 0) {
			return false;
		}
	}
	return true;
}

4. 写程序生成前 100 个素数。

#include <stdio.h>
#include <stdbool.h>

int main(void) {
   
	int prime[100] = {
    2 };
	int n = 1, candidate = 3;
	while (n < 100) {
   
		bool isPrime = true;
		for (int i = 0; i < n; i++) {
   
			if (candidate % prime[i] == 0) {
   
				isPrime = false;
				break;
			}
		}
		if (isPrime) {
   
			prime[n++] = candidate;
		}
		candidate++;
	}

	for (int i = 0; i < 100; i++) {
   
		printf("%d ", prime[i]);
	}
	printf("\n");

	return 0;
}

5

在密码学领域,对大整数进行素数测试是一个常见的问题。Fermat’s Test(费马测试)是一种基于费马小定理的素数测试算法,它可以用来快速判断一个数是否可能为素数。费马小定理表述如下:

如果 p p p 是一个素数,且 a a a 是不可被 p p p 整除的任意整数,则 a p − 1 ≡ 1 ( m o d p ) a^{p-1} \equiv 1 \pmod{p} ap11(modp)

Fermat’s Test 利用了这一定理:对于一个给定的数 n n n,选择一个随机整数 a a a,然后检查是否满足 a n − 1 ≡ 1 ( m o d n ) a^{n-1} \equiv 1 \pmod{n} an11(modn)。如果不满足,则 n n n 肯定不是素数;如果满足,则有可能是素数。通过多次选择不同的 a a a 进行测试,可以提高判断的准确性。

需要注意的是,虽然 Fermat’s Test 能够快速判断一个数是否可能为素数,但并不是绝对准确的。存在一些伪素数(pseudoprime),它们能够通过 Fermat’s Test 的检验,但实际上并不是素数。因此,在实际应用中,为了提高安全性,通常会结合其他素数测试方法来进行判断。

6. (a) 对于一个大小为N的数组,它的下标范围是多少?

对于一个大小为N的数组,它的下标范围是从0到N-1。数组的下标从0开始,到N-1结束,共计N个元素。

7. 如何计算arr[i]的地址?

要计算arr[i]的地址,可以使用以下公式:

address_of_arr_i = address_of_arr + i * size_of_each_element

其中,address_of_arr是数组arr的起始地址,i是要访问的元素的下标,size_of_each_element是数组中每个元素的大小(以字节为单位)。

例如,如果要计算arr[3]的地址,假设arr的起始地址是0x1000,每个元素占4个字节(int类型),则计算公式为:

address_of_arr_3 = 0x1000 + 3 * 4 = 0x100C

因此,arr[3]的地址是0x100C

8. 为什么程序员会有这样一个刻板印象:数组的效率比链表高?

程序员通常有这样一个刻板印象是因为数组和链表在访问和操作上有不同的性能特点,使得它们在不同的场景下具有不同的效率。

  1. 内存访问方式:数组在内存中是连续存储的,而链表的节点可以是分散存储的。在访问数组元素时,可以通过索引直接计算出元素的地址并进行访问,而在链表中,需要从头节点开始逐个遍历找到目标节点,因此数组的访问效率更高。

  2. 缓存友好性:现代计算机系统中,缓存起着非常重要的作用。由于数组元素在内存中是连续存储的,所以在访问数组时,可以更好地利用缓存预取机制,提高访问效率。而链表节点分散存储,可能会导致缓存未命中,降低访问效率。

  3. 插入和删除操作:在插入和删除操作上,链表比数组更高效。因为数组在插入和删除时需要移动大量元素,而链表只需要修改指针即可完成操作。

  4. 空间利用率:对于数组来说,需要预先分配一定大小的内存空间,而且大小固定。而链表可以动态分配内存,根据需要动态增长,因此在空间利用率上,链表更灵活。

综上所述,虽然数组和链表各有优势,但在大多数情况下,程序员更倾向于使用数组来实现一些数据结构,因为数组在访问上更高效,尤其是对于需要频繁访问元素的情况。

9. 写一个能计算数组大小的宏函数。

你可以使用以下宏函数来计算数组的大小:

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

这个宏函数使用了 sizeof 运算符来计算整个数组的大小,然后除以单个元素的大小,从而得到数组的元素个数。注意,这个宏函数只能用于在同一作用域内定义的数组,因为它依赖于编译器对数组的大小计算。

10. 写一个随机发牌的小程序:用户指定发几张牌,程序打印手牌。

输入:
Enter number of cards in hand: 5
输出:
Your hand: 7c 2s 5d as 2h
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define NUM_SUITS 4
#define NUM_RANKS 13

int main(void) {
   
	bool inHand[NUM_SUITS][NUM_RANKS] = {
    false };
	const char suits[NUM_SUITS] = {
    's', 'h', 'c', 'd' };
	const char ranks[NUM_RANKS] = {
    '2', '3', '4', '5', '6', '7', '8', '9', 't', 'j', 'q', 'k', 'a' };

	int n;
	printf("Enter number of cards in hand: ");
	scanf("%d"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

不好,商鞅要跑

谢谢咖啡

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

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

打赏作者

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

抵扣说明:

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

余额充值