3.11笔记3

3.11知识点3

  • 1. break 语句和 continue 语句有什么区别?
  • 2. 使用 goto 计算 1-2+3-4+......+99-100 的值。
  • 3. 输入一个整数,判断这个数是不是素数。
  • 4. 写程序生成前 100 个素数。
  • 5
  • 6. (a) 对于一个大小为N的数组,它的下标范围是多少?
  • 7. 如何计算`arr[i]`的地址?
  • 8. 为什么程序员会有这样一个刻板印象:数组的效率比链表高?
  • 9. 写一个能计算数组大小的宏函数。
  • 10. 写一个随机发牌的小程序:用户指定发几张牌,程序打印手牌。
  • 11. 为什么传递数组时,除了要传入数组名,还要传入长度?
  • 12. 二维数组`arr[M][N]`的本质是一个一维数组,这个一维数组有多少个元素,每个元素的类型是什么?`arr[i][j]`的地址是多少?为什么二维数组传递的时候,不能省略第二个维度?
  • 13. 什么是局部变量,什么是外部变量,它们的作用域分别是什么?
  • 14. 存储期限有哪些?局部变量默认的存储期限是什么?怎么改变局部变量的存储期限?
  • 15. 德州扑克:写一个程序循环读取 5 张手牌 (输入 0 结束程序),然后把手中的牌分为下面某一类:1.同花顺 2.四张 3.葫芦 (3 + 2) 4. 同花 5. 顺子 6.三张 7.两对 8. 一对 9.高牌。程序对话如下:
  • 16. 约瑟夫环:n 个人站成一圈,每个 m 个人处决一个人。假设这 n 个人的编号为 1, 2, ..., n,并且从 1 开始数,问最终活下来的人编号是多少?
  • 17. 约瑟夫排列:我们可以在此基础上定义约瑟夫排列,编号为 1, 2, ..., n 的 n 个人围成一个圈,每 m 个人移出一个人,直到移出所有的人。移出的顺序我们称为 (n, m)-约瑟夫排列。比如 (7, 3)-约瑟夫排列为 < 3, 6, 2, 7, 5, 1, 4>。请写一个程序,打印 (n, m)-约瑟夫排列。
  • 18. 什么是指针,什么是指针变量?
  • 19. 什么是野指针,对野指针进行解引用运算会发生什么现象?
  • 20. 指针可以进行哪些算术运算?
  • 21. 矩阵乘法。写一个函数实现两个矩阵相乘。
  • 22. 请总结一下指针和数组之间的关系。
  • 23. 删除有序数组中的连续重复元素 (保留一个)。
  • 24. 回型填充数组: 输入一个整数 n (n <= 10),构造一个 n*n 方阵,方阵数值从1开始递增,按照“右 下 左 上”的方式循环向内填充。
  • 25. (a) 字符串变量的初始化和字符指针的初始化有何不同?请举例说明。
  • 26. 利用 getchar() 实现类似 gets_s 的功能。
  • 27. 将包含字符数字的字符串分开,使得分开后的字符串前一部分是数字,后一部分是字母。
  • 28 .将字符串中的空格替换成`"%020"` 。
  • 29. 删除字符串中指定的字符。

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 13int 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", &n);srand((unsigned)time(NULL));while (n > 0) {int suit = rand() % NUM_SUITS;int rank = rand() % NUM_RANKS;if (!inHand[suit][rank]) {inHand[suit][rank] = true;n--;printf("%c%c ", ranks[rank], suits[suit]);}}printf("\n");return 0;
}

11. 为什么传递数组时,除了要传入数组名,还要传入长度?

在C语言中,数组作为函数参数传递时,只传递数组名是不够的,因为数组名本身并不包含数组的长度信息。数组在内存中是一段连续的存储空间,而数组名只是数组首元素的地址,无法确定数组的长度。

因此,为了在函数内部正确地处理数组,需要额外传递数组的长度信息。这样函数才能知道数组的实际长度,避免越界访问等问题。通常情况下,可以将数组长度作为函数参数传递,或者使用特殊的约定,比如约定数组的最后一个元素为特定的值(如NULL),以表示数组的结束。

12. 二维数组arr[M][N]的本质是一个一维数组,这个一维数组有多少个元素,每个元素的类型是什么?arr[i][j]的地址是多少?为什么二维数组传递的时候,不能省略第二个维度?

二维数组arr[M][N]本质上是一个包含了M个元素的一维数组,每个元素是一个包含了N个元素的子数组。因此,二维数组arr[M][N]一共有M * N个元素,每个元素的类型是数组arr的第二维的类型,即arr的第二维是一个包含了N个元素的数组,因此每个元素的类型是包含了N个元素的数组类型,可以表示为arr[N]

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

address_of_arr_ij = address_of_arr + i * N * size_of_each_element + j * size_of_each_element

其中,address_of_arr是数组arr的起始地址,size_of_each_element是每个元素的大小(以字节为单位),ij分别是元素在第一维和第二维的下标。

关于为什么二维数组传递的时候不能省略第二个维度,原因是C语言中数组作为函数参数传递时,数组的第一维度可以省略,但第二维度必须指定。这是因为在函数参数中,数组名会被转换为指向数组首元素的指针,因此数组名本身并不包含数组的大小信息。为了在函数内部正确处理二维数组,需要知道第二维度的大小。

13. 什么是局部变量,什么是外部变量,它们的作用域分别是什么?

局部变量(local variable)是在函数或代码块内部定义的变量,它的作用域仅限于定义它的函数或代码块内部。局部变量在函数或代码块执行结束后会被销毁,不能在函数或代码块外部访问。

外部变量(external variable)是在函数或代码块外部定义的变量,它的作用域从定义处开始,直到文件结束或被另一个作用域覆盖为止。外部变量可以在文件中的任何地方被访问,但是如果在函数内部使用外部变量,则需要使用extern关键字进行声明。

总结一下:

  • 局部变量的作用域仅限于定义它的函数或代码块内部。
  • 外部变量的作用域从定义处开始,直到文件结束或被另一个作用域覆盖为止。
  • 外部变量可以在文件中的任何地方被访问,而局部变量只能在定义它的函数或代码块内部被访问。

14. 存储期限有哪些?局部变量默认的存储期限是什么?怎么改变局部变量的存储期限?

存储期限(storage duration)指的是变量在程序运行过程中所占用内存的持续时间,主要有以下几种:

  1. 静态存储期限(static storage duration):变量在程序运行期间始终存在,直到程序结束才会被销毁。静态变量(包括全局变量和静态局部变量)具有静态存储期限。

  2. 自动存储期限(automatic storage duration):变量在进入声明它的代码块时被创建,在离开代码块时被销毁。局部变量具有自动存储期限。

  3. 动态存储期限(dynamic storage duration):变量在程序运行时显式地分配内存,并在不再需要时显式地释放内存。动态存储期限的变量通过调用malloccallocnew等函数来分配内存。

局部变量默认具有自动存储期限。如果要改变局部变量的存储期限,可以将其声明为staticextern

  • 将局部变量声明为static,使其具有静态存储期限。静态局部变量在第一次进入声明它的代码块时初始化,且只初始化一次,在函数调用结束后不会被销毁,而是保留其值直到程序结束。
  • 将局部变量声明为extern,使其具有外部链接性,这样它的存储期限和作用域都会扩展到整个文件。

15. 德州扑克:写一个程序循环读取 5 张手牌 (输入 0 结束程序),然后把手中的牌分为下面某一类:1.同花顺 2.四张 3.葫芦 (3 + 2) 4. 同花 5. 顺子 6.三张 7.两对 8. 一对 9.高牌。程序对话如下:

Enter a card: 2s
Enter a card: 5s
Enter a card: 4s
Enter a card: 3s
Enter a card: 6s
Straight flushEnter a card: 8c
Enter a card: as
Enter a card: 8c
Duplicate card; ignored.
Enter a card: 7c
Enter a card: ad
Enter a card: 3h
PairEnter a card: 6s
Enter a card: d2
Bad card; ignored.
Enter a card: 2d
Enter a card: 9c
Enter a card: 4h
Enter a card: ts
High cardEnter a card: 0
#include <stdbool.h> 
#include <stdio.h>
#include <stdlib.h>#define NUM_RANKS 13
#define NUM_SUITS 4
#define NUM_CARDS 5int num_in_rank[NUM_RANKS];
int num_in_suit[NUM_SUITS];
bool straight, flush, four, three;
int pairs; /* can be 0, 1, or 2 */void read_cards(void);
void analyze_hand(void);
void print_result(void);int main(void)
{for (;;) {read_cards();analyze_hand();print_result();}
}void read_cards(void)
{bool card_exists[NUM_RANKS][NUM_SUITS];char ch, rank_ch, suit_ch;int rank, suit;bool bad_card;int cards_read = 0;for (rank = 0; rank < NUM_RANKS; rank++) {num_in_rank[rank] = 0;for (suit = 0; suit < NUM_SUITS; suit++)card_exists[rank][suit] = false;}for (suit = 0; suit < NUM_SUITS; suit++)num_in_suit[suit] = 0;while (cards_read < NUM_CARDS) {bad_card = false;printf("Enter a card: ");rank_ch = getchar();switch (rank_ch) {case '0': exit(EXIT_SUCCESS);case '2': rank = 0; break;case '3': rank = 1; break;case '4': rank = 2; break;case '5': rank = 3; break;case '6': rank = 4; break;case '7': rank = 5; break;case '8': rank = 6; break;case '9': rank = 7; break;case 't': case 'T': rank = 8; break;case 'j': case 'J': rank = 9; break;case 'q': case 'Q': rank = 10; break;case 'k': case 'K': rank = 11; break;case 'a': case 'A': rank = 12; break;default: bad_card = true;}suit_ch = getchar();switch (suit_ch) {case 'c': case 'C': suit = 0; break;case 'd': case 'D': suit = 1; break;case 'h': case 'H': suit = 2; break;case 's': case 'S': suit = 3; break;default: bad_card = true;}// read remaining characters of this linewhile ((ch = getchar()) != '\n')if (ch != ' ') bad_card = true;if (bad_card)printf("Bad card; ignored.\n");else if (card_exists[rank][suit])printf("Duplicate card; ignored.\n");else {num_in_rank[rank]++;num_in_suit[suit]++;card_exists[rank][suit] = true;cards_read++;}}
}void analyze_hand(void)
{int num_consec = 0;int rank, suit;straight = false;flush = false;four = false;three = false;pairs = 0;/* check for flush */for (suit = 0; suit < NUM_SUITS; suit++)if (num_in_suit[suit] == NUM_CARDS)flush = true;/* check for straight */rank = 0;while (num_in_rank[rank] == 0) rank++;for (; rank < NUM_RANKS && num_in_rank[rank] > 0; rank++)num_consec++;if (num_consec == NUM_CARDS) {straight = true;return;}/* check for 4-of-a-kind, 3-of-a-kind, and pairs */for (rank = 0; rank < NUM_RANKS; rank++) {if (num_in_rank[rank] == 4) four = true;if (num_in_rank[rank] == 3) three = true;if (num_in_rank[rank] == 2) pairs++;}
}void print_result(void)
{if (straight && flush) printf("Straight flush");else if (four) printf("Four of a kind");else if (three && pairs == 1) printf("Full house");else if (flush) printf("Flush");else if (straight) printf("Straight");else if (three) printf("Three of a kind");else if (pairs == 2) printf("Two pairs");else if (pairs == 1) printf("Pair");else printf("High card");printf("\n\n");
}

16. 约瑟夫环:n 个人站成一圈,每个 m 个人处决一个人。假设这 n 个人的编号为 1, 2, …, n,并且从 1 开始数,问最终活下来的人编号是多少?

约瑟夫环(Josephus problem)是一个经典的数学问题,描述如下:n个人围成一圈,从第一个人开始报数,报到第m个人的时候,该人被杀死;然后下一个人继续报数,直到剩下最后一个人。问最后一个活着的人原来的编号是多少。

有一个经典的解法使用递归来求解,可以表示为:

f(n, m) = (f(n - 1, m) + m) % n
f(1, m) = 0

其中,f(n, m) 表示 n 个人中最后存活的人的编号,m 表示每次报数到第 m 个人被杀死。

下面是一个使用递归解决约瑟夫环问题的 C 代码示例:

int josephus(int n, int m) {if (n == 1) {return 0;} else {return (josephus(n - 1, m) + m) % n;}
}int main() {int n = 5; // 5 个人int m = 2; // 每次报数到第 2 个人被杀死printf("最后活下来的人的编号是:%d\n", josephus(n, m) + 1); // 注意编号是从 1 开始的return 0;
}

这段代码中,josephus 函数用来计算最后活下来的人的编号,main 函数用来测试该函数。

17. 约瑟夫排列:我们可以在此基础上定义约瑟夫排列,编号为 1, 2, …, n 的 n 个人围成一个圈,每 m 个人移出一个人,直到移出所有的人。移出的顺序我们称为 (n, m)-约瑟夫排列。比如 (7, 3)-约瑟夫排列为 < 3, 6, 2, 7, 5, 1, 4>。请写一个程序,打印 (n, m)-约瑟夫排列。

这里是一个打印 (n, m)-约瑟夫排列的简单程序,使用了循环来模拟移出人的过程:

#include <stdio.h>void josephus_permutation(int n, int m) {int i, j, count;int people[n];for (i = 0; i < n; i++) {people[i] = i + 1;}printf("<");count = n;i = 0;while (count > 0) {for (j = 1; j < m; j++) {while (people[i] == 0) {i = (i + 1) % n;}i = (i + 1) % n;}while (people[i] == 0) {i = (i + 1) % n;}printf("%d", people[i]);count--;if (count > 0) {printf(", ");}people[i] = 0;}printf(">\n");
}int main() {int n = 7;int m = 3;josephus_permutation(n, m);return 0;
}

这个程序首先创建了一个数组 people 来表示每个人的编号,然后使用循环来模拟移出人的过程。在每一轮中,根据规则移出一个人,并将该人的编号打印出来,直到所有人都被移出。

18. 什么是指针,什么是指针变量?

指针(pointer)是一个变量,其值为另一个变量的内存地址。简单说,指针是用来存储内存地址的变量。指针可以指向任何数据类型(整数、字符、数组、函数等)的内存地址。

指针变量(pointer variable)是存储内存地址的变量。它包含了一个内存地址,可以指向内存中的某个位置,从而可以通过该地址访问或修改存储在该位置的数据。

例如,在C语言中,可以通过以下方式定义一个整型指针变量:

int *ptr;

这里ptr是一个指针变量,可以指向一个整型变量的地址。

19. 什么是野指针,对野指针进行解引用运算会发生什么现象?

野指针(dangling pointer)是指指向已经释放或者无效的内存地址的指针。野指针可能会导致程序运行时的不确定行为,因为它们指向的内存地址可能已经被其他程序使用,或者已经被系统回收。

对野指针进行解引用运算会导致未定义的行为,因为解引用操作实际上是试图访问指针所指向的内存地址的内容,而野指针指向的内存地址可能已经被其他程序使用或者已经被系统回收,这样就会导致访问无效的内存地址,可能会导致程序崩溃或者产生不可预料的结果。

为了避免野指针问题,应该始终确保指针指向有效的内存地址,避免在指针指向的内存被释放或者无效后继续使用该指针。

20. 指针可以进行哪些算术运算?

指针可以进行以下几种算术运算:

  1. 指针加法:可以将一个整数加到指针上,以移动指针指向的地址。例如,ptr + 1 将指针移动到下一个地址位置。

  2. 指针减法:可以将一个整数从指针上减去,以移动指针指向的地址。例如,ptr - 1 将指针移动到前一个地址位置。

  3. 指针与指针之间的减法:可以将两个指针相减,得到它们之间相差的元素个数。例如,(ptr2 - ptr1) 将返回两个指针之间相差的元素个数。

  4. 比较运算:可以对两个指针进行比较运算,判断它们是否指向同一个位置或者哪一个指针指向的位置在另一个之前。

21. 矩阵乘法。写一个函数实现两个矩阵相乘。

以下是一个简单的C程序,实现了两个矩阵的乘法运算:

#include <stdio.h>#define ROW1 2
#define COL1 3
#define ROW2 3
#define COL2 2void matrix_multiply(int mat1[][COL1], int mat2[][COL2], int result[][COL2]) {int i, j, k;for (i = 0; i < ROW1; i++) {for (j = 0; j < COL2; j++) {result[i][j] = 0;for (k = 0; k < COL1; k++) {result[i][j] += mat1[i][k] * mat2[k][j];}}}
}void display_matrix(int mat[][COL2], int row, int col) {int i, j;for (i = 0; i < row; i++) {for (j = 0; j < col; j++) {printf("%d ", mat[i][j]);}printf("\n");}
}int main() {int mat1[ROW1][COL1] = {{1, 2, 3}, {4, 5, 6}};int mat2[ROW2][COL2] = {{7, 8}, {9, 10}, {11, 12}};int result[ROW1][COL2];matrix_multiply(mat1, mat2, result);printf("Matrix 1:\n");display_matrix(mat1, ROW1, COL1);printf("\nMatrix 2:\n");display_matrix(mat2, ROW2, COL2);printf("\nResult Matrix:\n");display_matrix(result, ROW1, COL2);return 0;
}

这个程序定义了两个矩阵mat1mat2,分别是一个2x3和一个3x2的矩阵,然后调用matrix_multiply函数计算它们的乘积,并将结果存储在result矩阵中。最后,通过display_matrix函数显示原始矩阵和结果矩阵。

22. 请总结一下指针和数组之间的关系。

指针和数组在C语言中有着密切的关系,可以总结如下:

  1. 数组名是指向数组第一个元素的指针:在大多数情况下,数组名被编译器解释为指向数组第一个元素的指针。例如,对于数组int arr[5]arr可以被视为&arr[0],即指向第一个元素的指针。

  2. 指针可以像数组一样进行偏移:指针可以通过加法和减法运算来访问数组中的元素。例如,ptr + 1将指向数组中的下一个元素。

  3. 数组名不能进行赋值:由于数组名被视为指向常量的指针,因此不能将数组名用于赋值操作。例如,arr = &some_other_array[0]是非法的。

  4. 指针可以被用来遍历数组:通过递增指针来遍历数组是一种常见的方法。例如,可以使用for循环和指针来遍历数组中的所有元素。

  5. 数组名作为函数参数时会被转换为指针:当将数组名作为参数传递给函数时,实际上传递的是指向数组第一个元素的指针,而不是整个数组。

23. 删除有序数组中的连续重复元素 (保留一个)。

int removeDuplicates(int* arr, int n){int i, j = 1;for (i = 1; i < n; i++) {if (arr[i] != arr[j-1]) {arr[j] = arr[i];j++;}}return j;
}

24. 回型填充数组: 输入一个整数 n (n <= 10),构造一个 n*n 方阵,方阵数值从1开始递增,按照“右 下 左 上”的方式循环向内填充。

你可以使用如下的 C 代码来实现回型填充数组的功能:

#include <stdio.h>void fillMatrix(int n, int mat[][n]) {int value = 1;int top = 0, bottom = n - 1, left = 0, right = n - 1;int direction = 0; // 0: right, 1: down, 2: left, 3: upwhile (top <= bottom && left <= right) {if (direction == 0) {for (int i = left; i <= right; i++) {mat[top][i] = value++;}top++;} else if (direction == 1) {for (int i = top; i <= bottom; i++) {mat[i][right] = value++;}right--;} else if (direction == 2) {for (int i = right; i >= left; i--) {mat[bottom][i] = value++;}bottom--;} else if (direction == 3) {for (int i = bottom; i >= top; i--) {mat[i][left] = value++;}left++;}direction = (direction + 1) % 4;}
}void printMatrix(int n, int mat[][n]) {for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {printf("%d\t", mat[i][j]);}printf("\n");}
}int main() {int n;printf("Enter the value of n (n <= 10): ");scanf("%d", &n);int mat[n][n];fillMatrix(n, mat);printf("The filled matrix is:\n");printMatrix(n, mat);return 0;
}

这段代码中,fillMatrix函数实现了回型填充数组的逻辑,printMatrix函数用于打印填充后的数组。在main函数中,用户输入矩阵的大小 n,然后调用fillMatrixprintMatrix函数来填充和打印矩阵。

25. (a) 字符串变量的初始化和字符指针的初始化有何不同?请举例说明。

在 C 语言中,字符串变量的初始化和字符指针的初始化有一些不同。

  1. 字符串变量的初始化:字符串变量可以使用字符串常量来初始化。在 C 语言中,字符串常量是由双引号括起来的字符序列。例如:

    char str[] = "Hello, World!";
    

    这里的 str 是一个字符数组,它会被初始化为包含字符串常量 “Hello, World!” 的内容。

  2. 字符指针的初始化:字符指针可以指向字符串常量,也可以指向字符数组。指向字符串常量的字符指针可以通过直接赋值来初始化。例如:

    char *ptr = "Hello, World!";
    

    这里的 ptr 是一个字符指针,它指向字符串常量 “Hello, World!” 的第一个字符。需要注意的是,字符串常量是不可修改的,所以尽管 ptr 是一个指针,但不能通过它来修改字符串的内容。

另外,如果要使用字符指针指向字符数组来初始化,可以直接将数组名赋值给指针,因为数组名会被解释为指向数组第一个元素的指针。例如:

char str[] = "Hello, World!";
char *ptr = str; // ptr 指向字符数组 str

这样,ptr 就指向了数组 str 的第一个元素。

26. 利用 getchar() 实现类似 gets_s 的功能。

可以使用getchar()函数逐字符读取输入,并将读取的字符存储到一个字符数组中,直到遇到换行符为止,从而实现类似gets_s函数的功能。以下是一个示例代码:

#include <stdio.h>void my_gets_s(char *str, int size) {int i = 0;char c;// 读取字符,直到遇到换行符或者数组满了为止while ((c = getchar()) != '\n' && i < size - 1) {str[i++] = c;}// 添加字符串结束标志str[i] = '\0';
}int main() {char str[100];printf("Enter a string: ");my_gets_s(str, sizeof(str));printf("You entered: %s\n", str);return 0;
}

在这个示例中,my_gets_s函数模拟了gets_s函数的行为,通过getchar()逐字符读取输入,并将字符存储到字符数组str中,直到遇到换行符或者数组满了为止。然后在数组末尾添加字符串结束标志\0,以构成一个完整的字符串。

27. 将包含字符数字的字符串分开,使得分开后的字符串前一部分是数字,后一部分是字母。

输入: "h1ell2o3"
输出: "123hello"
void seperate(char* str) {char digits[N], alphas[N];int i = 0, j = 0;char* p = str;while (*p) {if (isdigit(*p)) {digits[i++] = *p;} else {alphas[j++] = *p;}p++;}digits[i] = '\0';alphas[j] = '\0';strcpy(str, digits);strcat(str, alphas);
}

28 .将字符串中的空格替换成"%020"

输入: "hello world how "
输出: "hello%020world%020how%020"
void substitute_space(char* str) {char substitute[N];int i = 0;char* p = str;while (*p) {if (*p == ' ') {substitute[i] = '%';substitute[i + 1] = '0';substitute[i + 2] = '2';substitute[i + 3] = '0';i += 4;} else {substitute[i++] = *p;}p++;}substitute[i] = '\0';strcpy(str, substitute);
}

29. 删除字符串中指定的字符。

输入: "abcdaefaghiagkl", 'a'
输出: "bcdefghigkl"
void delete_character(char* str, char ch) {char tmp[N];int i = 0;char* p = str;while (*p) {if (*p != ch) {tmp[i++] = *p;}p++;}tmp[i] = '\0';strcpy(str, tmp);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/738008.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

wins10安装ffmpeg

官网下载 点击进入官网&#xff1a;ffmpeg&#xff0c;官网地址&#xff1a;https://ffmpeg.org/download.html 点击上图中Windows图标选中后下面显示的第一行进入如下界面&#xff0c;在release builds第一个绿框里面选择一个版本下载&#xff1a; 下载好之后解压后&#xf…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:PatternLock)

图案密码锁组件&#xff0c;以九宫格图案的方式输入密码&#xff0c;用于密码验证场景。手指在PatternLock组件区域按下时开始进入输入状态&#xff0c;手指离开屏幕时结束输入状态完成密码输入。 说明&#xff1a; 该组件从API Version 9开始支持。后续版本如有新增内容&#…

GO语言-切片底层探索(上)

目录 1.前言 2. 算法题目 错误代码 3. 错误分析 4.总结&#xff1a; 5.正确代码&#xff1a; 6.本地测试代码&#xff1a; 1.前言 今天在力扣上写算法&#xff0c;遇到了一个比较"奇怪"的错误。由于自己使用了递归切片&#xff0c;导致一开始没有看明白&…

力扣最热100题——56.合并区间

吾日三省吾身 还记得梦想吗 正在努力实现它吗 可以坚持下去吗 目录 吾日三省吾身 力扣题号&#xff1a;56. 合并区间 - 力扣&#xff08;LeetCode&#xff09; 题目描述 Java解法一&#xff1a;排序然后原地操作 具体代码如下 Java解法二&#xff1a;new一个list&#xf…

(delphi11最新学习资料) Object Pascal 学习笔记---第7章第1节(引入类和对象)

第7章 对象 ​ 即使你没有面向对象编程&#xff08;OOP&#xff09;的详细知识&#xff0c;本章也将介绍每一个关键概念。如果你已经精通OOP&#xff0c;你可以相对快速地浏览材料&#xff0c;并将重点放在Object Pascal语言的细节上&#xff0c;与你可能已经掌握的其他语言进…

分布式ID(7):Zookeeper实现分布式ID生成

1 原理 实现方式有两种,一种通过节点,一种通过节点的版本号 节点的特性持久顺序节点(PERSISTENT_SEQUENTIAL) 他的基本特性和持久节点是一致的,额外的特性表现在顺序性上。在ZooKeeper中,每个父节点都会为他的第一级子节点维护一份顺序,用于记录下每个子节点创建的先后顺序…

虚拟机中安装Win98

文章目录 一、下载Win98二、制作可启动光盘三、VMware中安装Win98四、Qemu中安装Win981. Qemu的安装2. 安装Win98 Win98是微软于1998年发布的16位与32位混合的操作系统&#xff0c;也是一代经典的操作系统&#xff0c;期间出现了不少经典的软件与游戏&#xff0c;还是值得怀念的…

Kafka - This server does not host this topic-partition

问题描述 org.apache.kafka.common.errors.UnknownTopicOrPartitionException: This server does not host this topic-partition 原因分析 分区数据不在。producer 向不存在的 topic 发送消息 解决方案 用户可以检查 topic 是否存在设置 auto.create.topics.enable 参数

【LiveVideoStack】批量下载公众号文章

livevideostack暂停商业运行 官方建议关注文章保存,因此: y9000p 上运行: xiaoguyu / wechatDownload 大神太厉害了,工具软件很好很强大 windows 试试直接安装、编译、运行 zhangbin@LAPTOP-DFV9CMRA MINGW64 /g/ISOFT/livevideostack $ git clone https://github.com/xiao…

安卓多个listView拖动数据交换位置和拖动

注意这里只是给出大概思路&#xff0c;具体可以参考修改自己想要的 public class MainActivity extends AppCompatActivity {private ListView listView1;private ListView listView2;private ArrayAdapter<String> adapter1;private ArrayAdapter<String> adapter…

研发效能DevOps: OpenEuler 部署 drone 持续集成平台

目录 一、实验 1.环境 2.OpenEuler 部署 drone 持续集成平台 二、问题 1.drone登录失败 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 系统架构版本IP备注LinuxopenEuler22.03 LTS SP2 192.168.204.145&#xff08;动态&#xff09; 192.168.204.141&…

jenkins容器中安装python遇到问题

在Jenkins容器中安装配置Python时遇到问题 执行./configure --prefix/opt/python3/时遇到configure: error: no acceptable C compiler found in $PATH 这个问题就是缺少gcc编译环境。将gcc安装上即可&#xff1a; yum install -y gcc##前提是容器里的系统是cenos才可以&#…

`sh -c`命令——解决命令权限问题、一条命令中执行多个指令

sh -c在Shell中执行一个字符串作为命令&#xff0c;可以在一条命令中执行多个指令。 目录 语法如下&#xff1a;案例 使用sh -c与直接终端敲命令的区别使用sh -c解决命令权限问题 语法如下&#xff1a; sh -c command其中&#xff0c;command是要执行的命令或命令串。 案例 …

Excel下拉自动填充

1、选中需要下拉填充的单元格&#xff0c;按下Ctrl&#xff0c;然后再往下拖动填充。 下拉结果&#xff1a; 2、选中两个连续的单元格&#xff0c;往下拖动填充&#xff0c;可以填充增加两数差。 下拉结果&#xff1a; 本文为学习笔记&#xff0c;所参考文章均已附上链接&#…

【Node.js从基础到高级运用】六、创建第一个 Node.js 应用

创建第一个 Node.js 应用 在这一节中&#xff0c;我们将引导你创建你的第一个 Node.js 应用——一个简单的 “Hello World” 程序。这将帮助你熟悉 Node.js 项目的基本结构和模块化编程的概念。 步骤 1: 初始化项目 首先&#xff0c;创建一个新的目录作为项目的根目录&#…

设计模式前置了解uml图

在开发前&#xff0c;会进行系统的设计&#xff0c;而数据模型的设计大多通过 UML 类图实现。为了在 UML 类图中清晰地表达类之间的关系&#xff0c;需要对类之间的关系有一定的认识&#xff0c;并且了解相关的表达符号。 类之间的关系有以下几种&#xff1a; 组合 聚合 关联…

个人商城系统开源(配置支付宝支付!)

原文地址&#xff1a;个人商城系统开源&#xff08;配置支付宝支付&#xff01;&#xff09; - Pleasure的博客 下面是正文内容&#xff1a; 前言 由于近期实在没有什么话题可写和一些有趣的项目教程可以分享。所以我只能决定将我自己亲手编写的一个迷你迷你商城系统进行开源…

手机和电脑同步的好用记事本软件有哪些

我常常需要随手记录各种信息&#xff0c;以便随时查阅和使用。比如&#xff0c;在下班路上&#xff0c;我会用手机记录明天要处理的工作事项、购物清单&#xff0c;或是某个突然迸发的创意想法&#xff1b;而在办公室&#xff0c;我则需要在电脑上整理会议纪要、项目计划&#…

java学习(集合)

一.集合(主要是单列集合和双列集合) 1.集合的框架体系&#xff08;两大类&#xff09; 2.collection接口是实现类的特点&#xff1a; 1)collection实现子类可以存放多个元素&#xff0c;每个元素可以是Object 2)有效Collection的实现类&#xff0c;可以存放重复的元素&#…

案例分析篇04:数据库设计相关28个考点(1~8)(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章推荐: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12601310.html 【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例分析篇-…