当前位置: 首页 > news >正文

谭浩强C语言程序设计(4) 8章(下)

1、输入三个字符串按照字母顺序从小到大输出

#include <cstdio>  // 包含cstdio头文件,用于输入输出函数
#include <cstring> // 包含cstring头文件,用于字符串处理函数#define N 20       // 定义字符串的最大长度为20// 函数:交换两个字符串的内容
void sort(char* strA, char* strB) {char temp[N];  // 定义一个临时数组,用于存储其中一个字符串的内容strcpy(temp, strA);  // 将strA的内容复制到临时数组temp中strcpy(strA, strB);  // 将strB的内容复制到strA中strcpy(strB, temp);  // 将临时数组temp的内容(原来的strA)复制到strB中
}int main() {char str1[N], str2[N], str3[N]; // 定义三个字符串,用于存储用户输入puts("input the str1,str2,str3:"); // 提示用户输入三个字符串scanf("%s %s %s", str1, str2, str3); // 读取用户输入的三个字符串// 如果第一个字符串比第二个大,交换它们if (stricmp(str1, str2) > 0) { // 使用stricmp进行不区分大小写的比较sort(str1, str2);          // 调用sort函数交换str1和str2的内容}// 如果第二个字符串比第三个大,交换它们if (stricmp(str2, str3) > 0) {sort(str2, str3);          // 调用sort函数交换str2和str3的内容}// 如果第一个字符串比第三个大,交换它们if (stricmp(str1, str3) > 0) {sort(str1, str3);          // 调用sort函数交换str1和str3的内容}// 输出排序后的字符串printf("%s %s %s", str1, str2, str3);return 0; // 程序结束
}

        在C中,数组名在大多数情况下会被视为指向数组第一个元素的指针。当将数组作为参数传递给函数时,实际上传递的是数组的首地址,也就是指针的值传递。这时候函数内部的指针是原指针的一个副本,但它们指向的是同一块内存地址。

        当使用strcpy函数时,比如strcpy(strA, strB),这里的strA和strB是传入的指针,指向main函数中的数组。strcpy的作用是将strB指向的字符串内容复制到strA指向的内存空间中。因此,操作的是指针所指向的内存区域,而不是指针本身的值。这样,原数组的内容就被修改了。

        虽然指针本身是副本,但它们指向的是同一块内存地址。通过副本指针去修改内存中的数据,自然会影响原数据,因为原指针也指向同一块内存。

图解:

1、初始状态

2、strcpy(temp,strA); 

3、strcpy(strA,strB); 

4、strcpy(strB,temp);

 2、输入10个数,最小的数和第一个数交换,最大的数和最后一个数交换

#include <cstdio>#define N 5  // 定义数组长度// 输入函数:为数组元素赋值
void input(int* num) {for (int i = 0; i < N; ++i) {printf("input the No.%d num:", i + 1);scanf("%d", num + i);  // 等价于 &num[i],指针偏移方式访问数组元素}
}// 获取最小值索引函数
int getMinIndex(int* num) {int minIndex = 0;          // 初始化为首元素索引int min = *num;            // 初始化为首元素值for (int i = 0; i < N; ++i) {if (min > *(num + i)) {  // 发现更小值时更新min = *(num + i);minIndex = i;}}return minIndex;
}// 获取最大值索引函数
int getMaxIndex(int* num) {int maxIndex = 0;          // 初始化为首元素索引int max = *num;            // 初始化为首元素值for (int i = 0; i < N; ++i) {if (max < *(num + i)) {  // 发现更大值时更新max = *(num + i);maxIndex = i;}}return maxIndex;
}/*** 极值交换函数(已修复原逻辑问题)* 执行顺序:* 1. 交换最小值到数组首部* 2. 在更新后的数组中重新获取最大值位置* 3. 交换最大值到数组末尾*/
void minAndMax(int* num) {// 第一阶段:处理最小值交换 --------------------------int minIndex = getMinIndex(num);  // 获取原始最小值位置int temp;// 执行最小值交换操作temp = *num;                // 暂存原首元素值*num = *(num + minIndex);   // 将最小值写入首元素位置*(num + minIndex) = temp;   // 将原首元素值写入原最小值位置// 第二阶段:处理最大值交换 --------------------------/* 关键改进点:在交换最小值后重新获取最大值位置* 解决原版本最大值可能被意外移动的问题*/int maxIndex = getMaxIndex(num);  // 获取当前数组最大值位置// 执行最大值交换操作temp = *(num + maxIndex);         // 暂存当前最大值*(num + maxIndex) = *(num + N-1); // 将末元素值写入原最大值位置*(num + N-1) = temp;              // 将最大值写入末元素位置
}// 输出数组内容
void output(int* num) {for (int i = 0; i < N; ++i) {printf("%d ", num[i]);  // 使用数组下标方式访问元素}
}int main() {int num[N];          // 声明整型数组input(num);          // 调用输入函数minAndMax(num);      // 执行极值交换output(num);         // 输出结果return 0;            // 程序正常退出
}

3、输入n个整数实现向后或者向前移动m个单位

#include <cstdio>
#define N 10  // 定义数组最大容量(最多存储10个元素)/*** 实现数组循环右移操作* @param a     要操作的数组指针(会被修改)* @param len   数组实际使用的有效长度(必须小于等于N)* @param place 实际移动的位置数(经过规范化处理后的值)* * 实现原理:* 1. 创建临时数组存储移动后的结果* 2. 通过取模运算实现循环右移* 3. 将结果复制回原数组*/
void move(int* a, int len, int place) {int temp[len];  // 创建临时数组用于存储移动后的元素// 核心循环:将每个元素移动到新位置for (int i = 0; i < len; ++i) {// 计算新下标公式:(原下标+移动位数)%数组长度// 当计算结果超过数组长度时,自动从数组开头继续计算temp[(i + place) % len] = a[i]; // 例:len=5,place=7时等同于place=2}// 将排序结果写回原数组for (int i = 0; i < len; ++i) {a[i] = temp[i];  // 逐个元素复制回原数组}
}/*** 输出数组元素* @param a   要输出的数组指针* @param len 数组实际有效长度* * 输出格式:元素间用空格分隔,最后换行*/
void output(int* a, int len) {for (int i = 0; i < len; ++i) {printf("%d ", a[i]);  // 遍历输出每个元素}printf("\n");  // 输出完成后换行
}int main() {int a[N];       // 存储数据的数组(物理容量为10)int len = 0;    // 用户实际使用的元素个数int place = 0;  // 原始输入的移动位数// 第一阶段:获取用户输入puts("how many number?");scanf("%d", &len);  // 注意:此处未校验len>10的情况printf("input the %d numbers:", len);for (int i = 0; i < len; ++i) {scanf("%d", &a[i]);  // 连续读取指定数量的整数}// 第二阶段:获取并处理移动位数printf("how many place do you want move?");scanf("%d", &place);// 关键处理:位移规范化(支持负数和超长位移)// 1. place % len 处理过大位移(如place=15,len=10→5)// 2. +len 保证结果非负(处理负数位移)// 3. 再次%len 确保最终值在[0,len-1]范围内place = (place % len + len) % len;  // 示例:place=-3,len=5→2// 第三阶段:执行移动并输出结果move(a, len, place);output(a, len);return 0;  // 正常退出程序
}

 4、N个人围成一圈按照顺序排号。从第一个开始报数(1到3)凡是报号为3的出圈,最后剩下的那个是刚开始的几号?(约瑟夫环问题)😒

#include <cstdio> // 包含标准输入输出库
#define N 10      // 定义数组的最大容量为10int main() {int arr[N];                       // 定义一个大小为N的数组,用于标记每个人的状态(1表示在场,0表示出局)int totalPeople = 0;              // 总人数int current = 0;                  // 当前的位置指针(从0开始)int count = 0;                    // 报数计数器(记录当前数到第几个人)printf("How many people? ");      // 提示用户输入总人数scanf("%d", &totalPeople);        // 读取用户输入的总人数int remaining = totalPeople;      // 剩余人数,初始值等于总人数for (int i = 0; i < totalPeople; ++i) {arr[i] = 1;                   // 初始化数组,所有人的状态设置为1(在场)}// 模拟报数过程,直到只剩1人while (remaining > 1) {if (arr[current] == 1) {      // 如果当前位置的人在场count++;                  // 报数加1if (count == 3) {         // 如果报数到3arr[current] = 0;     // 将当前位置的人标记为出局remaining--;          // 剩余人数减1count = 0;            // 重置报数计数器printf("%d out ", current); // 输出出局的人的编号}}current = (current + 1) % totalPeople; // 移动到下一个位置(环形移动)}printf("\n");                     // 换行for (int i = 0; i < totalPeople; ++i) {if (arr[i] == 1) {            // 查找最后剩下的那个人printf("The last survivor is %d\n", i + 1); // 输出最后剩下的人的编号(加1是为了将索引转换为实际编号)}}return 0;                         // 程序结束
}

 5、求字符串长度

#include <cstdio>
#define N 20int getLength(char* p){int i = 0,length = 0;while(p[i] != '\0' && i < N){length++;i++;}return length;
}int main(){char str[N];printf("input the string:");scanf("%s",str);printf("the length of string is:%d", getLength(str));
}

6、将包含N个字符的字符串从第M个位置开始复制到另一个字符数组,并输出

#include <cstdio> // 包含标准输入输出库
#define N 20      // 定义数组的最大容量为20// 复制字符串的部分功能
void copy(char* p1, char* p2, int start) {int i = start - 1; // 从用户指定的起始位置开始(注意:数组索引从0开始,所以需要减1)int j = 0;         // 目标字符串的索引// 从起始位置开始复制,直到遇到字符串结束符'\0'或超出数组范围while (p1[i] != '\0' && i < N) {p2[j++] = p1[i++]; // 将源字符串p1的字符复制到目标字符串p2中}p2[j] = '\0'; // 在目标字符串末尾添加字符串结束符'\0'
}int main() {char str1[N]; // 定义第一个字符串数组,用于存储用户输入的源字符串char str2[N]; // 定义第二个字符串数组,用于存储复制后的结果字符串int start = 0; // 用户指定的起始位置// 提示用户输入源字符串printf("input the str1: ");scanf("%s", str1); // 读取用户输入的源字符串// 提示用户输入起始位置printf("input the start: ");scanf("%d", &start); // 读取用户输入的起始位置// 调用复制函数,从起始位置开始复制字符串copy(str1, str2, start);// 输出目标字符串(复制后的结果)printf("%s", str2);return 0; // 程序结束
}

 7、输入5x5矩阵,最大的元素放在中心,四个角上是最小的元素,大小顺序是从左到右,从上到下放😒

#include <cstdio>
#define N 5  // 定义矩阵的大小为5x5// 函数作用:处理矩阵,把最大值放到中心,四个角放最小值
void change(int (*point)[N]) {int a[4];  // 用于存储四个最小值int b[4];  // 用于存储四个角的原始值// 1. 找到最大的元素并放到中心位置int max = point[0][0];  // 假设第一个元素是最大值for (int i = 0; i < N; ++i) {for (int j = 0; j < N; ++j) {if (point[i][j] > max) {  // 如果当前矩阵的值比假设的最大值更大max = point[i][j];    // 更新最大值}}}point[2][2] = max;  // 将最大值放置到矩阵中心(即坐标 [2][2])// 2. 保存四个角的原始值b[0] = point[0][0];  // 左上角b[1] = point[0][4];  // 右上角b[2] = point[4][0];  // 左下角b[3] = point[4][4];  // 右下角// 3. 找到四个最小值,并将它们替换到四个角的位置for (int k = 0; k < 4; ++k) {  // 多次循环找到四个最小值int min_val = 1000000;  // 假设矩阵值不会超过这个数值int row = -1, col = -1; // 记录最小值的位置// 遍历矩阵,找到当前最小值for (int i = 0; i < N; ++i) {for (int j = 0; j < N; ++j) {if (point[i][j] < min_val) {  // 如果当前值比假设的最小值更小min_val = point[i][j];    // 更新最小值row = i;                 // 记录最小值的行号col = j;                 // 记录最小值的列号}}}a[k] = min_val;  // 保存当前最小值point[row][col] = b[k];  // 将最小值的位置替换为原始角的值}// 4. 将四个最小值放置到四个角point[0][0] = a[0];  // 左上角point[0][4] = a[1];  // 右上角point[4][0] = a[2];  // 左下角point[4][4] = a[3];  // 右下角
}int main() {int arr[N][N];  // 定义一个5x5的整数矩阵// 输入矩阵printf("Enter the 5x5 matrix:\n");for (int i = 0; i < N; ++i) {printf("Enter row %d (numbers separated by spaces):\n", i + 1);for (int j = 0; j < N; ++j) {scanf("%d", &arr[i][j]);  // 读取每一行的数值}}// 打印原始矩阵printf("\nThe original matrix is:\n");for (int i = 0; i < N; ++i) {for (int j = 0; j < N; ++j) {printf("%d ", arr[i][j]);  // 打印每一行的数值}printf("\n");}// 调用函数处理矩阵change(arr);  // 调用change函数,处理矩阵// 打印修改后的矩阵printf("\nThe modified matrix is:\n");for (int i = 0; i < N; ++i) {for (int j = 0; j < N; ++j) {printf("%d ", arr[i][j]);  // 打印处理后的矩阵}printf("\n");}return 0;  // 程序正常结束
}

书上写的有点难懂哦,呜呜呜。

8、输入十个等长的字符串,对字符串排序并输出排序好的字符串

#include <cstdio>
#include <cstring>
#define N 3
#define M 6// 折半插入排序
void sort(char (*p)[M]) {int high, low, mid;char temp[M];  // 使用临时数组保存当前待插入的字符串for (int i = 1; i < N; ++i) {high = i - 1;low = 0;strcpy(temp, p[i]);  // 将当前字符串复制到临时数组while (low <= high) {mid = (low + high) / 2;if (stricmp(p[mid], temp) > 0) {high = mid - 1;} else {low = mid + 1;}}// 将 [low, i-1] 区间的字符串后移一位for (int j = i - 1; j >= low; j--) {strcpy(p[j + 1], p[j]);  // 复制字符串内容}strcpy(p[low], temp);  // 将临时字符串插入到正确位置}
}int main() {char str[N][M], (*point)[M];for (int i = 0; i < N; ++i) {printf("Enter string %d (max length %d): ", i + 1, M - 1);scanf("%s", str[i]);  // 输入字符串}printf("\nUnsorted array of strings:\n");for (int i = 0; i < N; ++i) {printf("%s\n", str[i]);  // 输出未排序的数组}point = str;sort(point);  // 调用排序函数printf("\nSorted array of strings:\n");for (int i = 0; i < N; ++i) {printf("%s\n", str[i]);  // 输出排序后的数组}return 0;
}

在代码中,strcpy(p[j + 1], p[j]); 的作用是将字符串 p[j] 复制到 p[j + 1]。这是因为数组中的元素是字符数组(即字符串),而直接赋值 p[j + 1] = p[j] 是不允许的,因为数组名是常量指针,不能直接被赋值。

9、矩阵法求如下定积分

\int_{0}^{1}sinxdx         

\int_{-1}^{1}cosxdx

\int_{0}^{2}e^{x}dx

10、一个班4个学生5门课程,实现下面的函数

(1)求第一门课程的平均分

(2)算出两门课不及格的学生的总分和平均分

(3)输出全部成绩在85以上的学生或者是平均分在90以上的学生

#include <cstdio> // 包含标准输入输出库// 定义学生数量(N)、课程数量(M)和课程名称的最大长度(L)
#define N 4  // 学生数量
#define M 5  // 课程数量
#define L 20 // 课程名称最大长度// 计算第一门课程的平均分
float getNo1ScoreAverage(float (*point)[M]) {float sum = 0; // 用于存储第一门课程的总成绩// 遍历所有学生,累加第一门课程的成绩for (int i = 0; i < N; ++i) {sum += *(*(point + i)); // point是一个指向二维数组的指针,*(*(point+i))相当于访问第i个学生的第1门课程的成绩}return sum / N; // 返回第一门课程的平均分
}// 找出至少有两门课程不及格的学生
void getTwoFail(float (*point)[M]) {int count = 0; // 不及格课程的数量float score = 0; // 单门课程成绩float arr[M];  // 用于存储学生的成绩float sum = 0; // 总成绩float average = 0;  // 平均分bool flag = true;  // 标记是否找到不合格学生// 遍历所有学生for (int i = 0; i < N; ++i) {count = 0; // 重置不及格课程计数// 遍历每个学生的课程成绩for (int j = 0; j < M; ++j) {score = *(*(point + i) + j); // 获取当前课程成绩arr[j] = score; // 将成绩存入数组if (score < 60) { // 如果成绩低于60分,表示不及格count++; // 不及格课程计数加1}}// 如果不及格课程数量大于等于2if (count >= 2) {flag = !flag; // 设置标记为找到不合格学生// 输出该学生的编号和所有成绩信息printf("The fail student is No.%d\n", i + 1);sum = 0; // 重置总成绩// 计算总成绩和平均分for (int k = 0; k < M; ++k) {sum += arr[k];}average = sum / M;printf("His score is :%3.2f and average is:%3.2f\n", sum, average);}}// 如果没有找到不合格学生if (flag) {printf("No fail student!!!\n");}
}// 找出平均分在90分以上或者每门成绩都在85分以上的学生
void getGood(float (*point)[M]) {float score = 0; // 单门课程成绩int count = 0; // 单门成绩在85以上的课程数float sum = 0; // 总成绩float average = 0;  // 平均分// 遍历所有学生for (int i = 0; i < N; ++i) {count = 0; // 重置课程计数sum = 0; // 重置总成绩// 遍历每个学生的课程成绩for (int j = 0; j < M; ++j) {score = *(*(point + i) + j); // 获取当前课程成绩if (score > 85) { // 如果成绩超过85分count++; // 计数加1}sum += score; // 累加总成绩}// 如果每门成绩都超过85分if (count == M) {printf("No.%d student's score all above 85\n!", i + 1);}average = sum / M; // 计算平均分// 如果平均分超过90分if (average > 90) {printf("No.%d student's average above 90!\n", i + 1);}}
}int main() {float scores[N][M], (*p)[M]; // 定义学生成绩的二维数组和指向它的指针// 输入学生成绩for (int i = 0; i < N; ++i) {printf("input the No.%d's student's scores:\n", i + 1); // 提示输入第i个学生的成绩for (int j = 0; j < M; ++j) {printf("input the score %d:", j + 1); // 提示输入第j门课程的成绩scanf("%f", &scores[i][j]); // 输入成绩并存入数组}}p = scores; // 指针p指向学生成绩数组printf("\n");// 输出第一门课程的平均分printf("The score 1's average is:%3.2f\n", getNo1ScoreAverage(p));// 查找并输出至少有两门课程不及格的学生信息getTwoFail(p);// 查找并输出平均分在90分以上或者每门成绩都在85分以上的学生信息getGood(p);return 0; // 程序结束
}

11、输入一堆字符串,有数字和非数字,将连续的数字视为一个整数并存放到数组,输出数组的元素

例如A123x456 1760? 302TAB5876

输出123 456 1760 302 5876这几个整数

#include <cstdio>
#include <cstring>
#include <cstdlib> // 包含 atoi 函数#define N 30 // 定义字符串和数组的最大长度/*** @brief 将字符数组转换为整数* @param temp 存储数字字符的数组(必须以'\0'结尾)* @return 转换后的整数值* @note 使用 atoi 实现转换,但需注意:*       - 若 temp 包含非数字字符,atoi 会截断前面的数字部分(如 "123a" 转成 123)*       - 若数值超出 int 范围,行为未定义*/
int convert(char temp[N]) {return atoi(temp); // 标准库函数,ASCII to integer
}/*** @brief 从字符串中提取连续数字并存入整数数组* @param str 输入的原始字符串* @param arr 用于存储提取结果的整数数组* @param strLen 输入字符串的长度* @param validCount 引用参数,用于返回实际提取的数字个数* @note 逻辑说明:*       1. 遍历字符串每个字符*       2. 当发现数字字符时,开始收集连续数字*       3. 将连续数字字符存入临时数组 temp*       4. 调用 convert 转换为整数并存入结果数组*/
void getData(char str[], int arr[], int strLen, int &validCount) {char temp[N];  // 临时存储数字字符的缓冲区int tempIndex = 0; // temp 数组的当前索引int arrIndex = 0;  // arr 数组的当前索引for (int i = 0; i < strLen; ++i) {// 发现数字字符时开始收集if (str[i] >= '0' && str[i] <= '9') {tempIndex = 0; // 重置临时数组索引// 收集连续数字字符(注意:未处理负数符号)while (i < strLen && (str[i] >= '0' && str[i] <= '9')) {// 潜在问题:若连续数字超过 N-1 个会导致缓冲区溢出// 建议添加:&& tempIndex < N-1temp[tempIndex++] = str[i++];}temp[tempIndex] = '\0'; // 添加字符串结束符// 转换并存储结果arr[arrIndex++] = convert(temp);validCount++; // 更新有效数字计数i--; // 回退一个字符,因为外层循环会执行 i++}}
}int main() {char str[N];     // 输入字符串缓冲区int arr[N];      // 存储提取结果的数组int validCount = 0; // 实际提取的有效数字个数// 输入处理puts("input the string:");gets(str); // 警告:存在缓冲区溢出风险!建议改用 fgets(str, N, stdin)// 计算有效长度(去除可能的换行符)int len = strlen(str);printf("Length: %d\n", len);// 执行核心提取逻辑getData(str, arr, len, validCount);// 输出结果(仅打印有效数据)printf("Extracted numbers: ");for (int i = 0; i < validCount; ++i) {printf("%d ", arr[i]);}return 0;
}

`atoi`是C标准库中的一个函数,用于将字符串转换为整数。用户可能在代码中看到它被用来处理从字符串中提取的数字部分,比如将"123"转换为123。但是字符数组的结尾必须是‘\0’

12、编写函数实现两个字符串的比较

#include <cstdio>  // 包含标准输入输出库的头文件#define N 10       // 定义宏 N,表示字符串的最大长度为 10// 定义一个函数 compare,用于比较两个字符串
int compare(char str1[], char str2[]) {int result = 0;                     // 初始化比较结果为 0for (int i = 0; i < N && (str1[i] != '\0' && str2[i] != '\0'); ++i) {// 遍历字符串,直到遇到字符 '\0' 或超过 N 的长度if (str1[i] != str2[i]) {       // 如果当前字符不相等result = str1[i] - str2[i]; // 计算ASCII码的差值,并赋值给 resultbreak;                      // 找到第一个不相等的字符后,跳出循环}}return result;  // 返回比较结果
}int main() {char str1[N], str2[N];  // 定义两个字符数组 str1 和 str2,用于存储用户输入的字符串puts("input the str1:");  // 提示用户输入第一个字符串gets(str1);               // 读取用户输入的字符串,存储到 str1 中puts("input the str2:");  // 提示用户输入第二个字符串gets(str2);               // 读取用户输入的字符串,存储到 str2 中int result = compare(str1, str2);  // 调用 compare 函数,比较两个字符串printf("result:%d", result);       // 输出比较结果return 0;  // 程序正常结束
}

13、指针数组实现输入月号,输出英文月号

#include <cstdio>int main() {// 定义一个字符串数组,存储12个月的英文名称const char* months[] = {"January",  // 1月"February", // 2月"March",    // 3月"April",    // 4月"May",      // 5月"June",     // 6月"July",     // 7月"August",   // 8月"September",// 9月"October",  // 10月"November", // 11月"December"  // 12月};puts("input the month:");int month;scanf("%d", &month);// 检查输入是否在有效范围内if (month >= 1 && month <= 12) {printf("%s\n", months[month - 1]);  // 使用 month - 1 调整索引} else {printf("Invalid month number. Please enter a number between 1 and 12.\n");}return 0;
}

15、使用双重指针实现对5个字符串排序输出

#include <cstdio>   // 输入输出函数
#include <cstdlib>  // 动态内存管理函数
#include <cstring>  // 字符串操作函数#define N 5         // 要处理的字符串数量
#define max 10      // 每个字符串的最大长度(包含空终止符)// 折半插入排序函数,对字符串指针数组进行不区分大小写排序
void sort(char** str) {int low, mid, high; // 二分查找的区间指针char* temp;         // 临时保存当前待插入字符串指针// 从第二个元素开始逐个插入到前面已排序序列for (int i = 0; i < N; ++i) {low = 0;        // 初始化查找区间起始位置high = i - 1;   // 初始化查找区间结束位置temp = str[i];  // 保存当前待插入的字符串指针// 二分查找插入位置(升序排列)while (low <= high) {mid = (low + high) / 2;// 使用不区分大小写的比较(注意:stricmp是Windows特有,Linux可用strcasecmp)if (stricmp(str[mid], temp) > 0) {high = mid - 1; // 中间值更大,调整上限} else {low = mid + 1;  // 中间值更小,调整下限}}// 将插入位置后的元素后移(移动指针而不是复制字符串内容)for (int j = i - 1; j >= low; j--) {str[j + 1] = str[j]; // 直接移动指针位置}// 将当前元素插入到正确位置str[low] = temp;}
}int main() {char* str[N]; // 字符串指针数组// 输入处理:为每个字符串动态分配内存for (int i = 0; i < N; ++i) {printf("input the string %d:", i + 1);str[i] = (char*)malloc(max * sizeof(char)); // 分配max字节内存scanf("%s", str[i]); // 注意:实际最多读取max-1个字符,需用户保证输入合规}// 调用排序函数对指针数组进行排序sort(str);// 输出排序结果puts("\nthe result:");for (int i = 0; i < N; ++i) {printf("%s ", str[i]);}// 改进建议:应在此处添加内存释放// for (int i = 0; i < N; ++i) {//     free(str[i]);// }return 0;
}

16、双重指针对输入的数字排序

#include <cstdio> // 包含标准输入输出库
#define N 5 // 定义数组的大小,这里为5// 折半插入排序函数,参数为指向指针的指针
void sort(int** pInt) {int low, mid, high; // 定义二分查找所需的变量int* temp; // 用于临时存储当前元素// 从第二个元素开始进行排序for (int i = 1; i < N; ++i) {low = 0; // 初始化二分查找的下边界high = i - 1; // 初始化二分查找的上边界temp = *(pInt + i); // 当前要插入的元素// 使用二分查找确定当前元素的插入位置while (low <= high) {mid = (low + high) / 2; // 计算中间位置if (*pInt[mid] > *temp) { // 如果中间位置的元素大于当前元素high = mid - 1; // 调整上边界} else {low = mid + 1; // 调整下边界}}// 将插入位置之后的元素后移一位,为当前元素腾出空间for (int j = i - 1; j >= low; --j) {pInt[j + 1] = pInt[j];}// 将当前元素插入到正确的位置pInt[low] = temp;}
}int main() {int arr[N]; // 定义一个存储输入数字的数组int* point[N]; // 指向数组元素的指针数组int** pInt; // 指向指针数组的指针// 读取用户输入的数字for (int i = 0; i < N; ++i) {printf("input the num%d:", i + 1); // 提示用户输入第i个数字scanf("%d", &arr[i]); // 读取用户输入的数字point[i] = &arr[i]; // 将指针数组的第i个元素指向数组的第i个元素}pInt = point; // 使 pInt 指向指针数组// 调用排序函数对指针数组进行排序sort(pInt);// 输出排序后的结果printf("Sorted array: ");for (int i = 0; i < N; ++i) {printf("%d ", *pInt[i]); // 通过指针数组访问并输出排序后的数字}return 0; // 程序正常结束
}

1. int arr[N];

  • 作用:声明了一个名为 arr 的整数数组。

  • 细节

    • N 是一个宏定义的常量,表示数组的大小(例如 #define N 5)。

    • 数组 arr 用于存储 N 个整数,可以通过下标访问和修改数组中的元素,例如 arr[0] 表示数组的第一个元素。

    • 数组的大小在编译时确定,因此 N 必须是一个常量。

2. int* point[N];

  • 作用:声明了一个指针数组 point

  • 细节

    • 指针数组是一个数组,其每个元素都是一个指向整数的指针(int*)。

    • 例如,point[0] 是一个指针,可以指向一个整数变量。

    • N 表示指针数组的大小,即指针数组中有 N 个指针。

    • 通常用于通过指针间接操作数组的元素,或者动态地管理内存

3. int** pInt;

  • 作用:声明了一个指向指针的指针 pInt

  • 细节

    • pInt 是一个指针,但它指向的不是一个普通的整数,而是指向一个指向整数的指针(即 int*)。

    • 简单来说,pInt 可以理解为一个“指针的指针”。

    • 通常用于指针数组的间接访问,或者动态二维数组的操作。

相关文章:

谭浩强C语言程序设计(4) 8章(下)

1、输入三个字符串按照字母顺序从小到大输出 #include <cstdio> // 包含cstdio头文件&#xff0c;用于输入输出函数 #include <cstring> // 包含cstring头文件&#xff0c;用于字符串处理函数#define N 20 // 定义字符串的最大长度为20// 函数&#xff1a;…...

AlexNet论文代码阅读

论文标题&#xff1a; ImageNet Classification with Deep Convolutional Neural Networks 论文链接&#xff1a; https://volctracer.com/w/BX18q92F 代码链接&#xff1a; https://github.com/dansuh17/alexnet-pytorch 内容概述 训练了一个大型的深度卷积神经网络&#xf…...

62.病毒在封闭空间中的传播时间|Marscode AI刷题

1.题目 问题描述 在一个封闭的房间里摆满了座位&#xff0c;每个座位东西向和南北向都有固定 1 米的间隔。座位上坐满了人&#xff0c;坐着的人可能带了口罩&#xff0c;也可能没有带口罩。我们已经知道房间里的某个人已经感染了病毒&#xff0c;病毒的传播速度是每秒钟感染距…...

Elixir语言的安全开发

Elixir语言的安全开发 引言 在当今这个互联网高度发展的时代&#xff0c;软件的安全性变得越来越重要。随着网络攻击的增多&#xff0c;软件漏洞的频繁暴露&#xff0c;开发者面临着前所未有的安全挑战。Elixir&#xff0c;作为一种现代化的函数式编程语言&#xff0c;以其高…...

Rust 条件语句

Rust 条件语句 在编程语言中&#xff0c;条件语句是进行决策和实现分支逻辑的关键。Rust 语言作为一门系统编程语言&#xff0c;其条件语句的使用同样至关重要。本文将详细介绍 Rust 中的条件语句&#xff0c;包括其基本用法、常见场景以及如何避免常见错误。 基本用法 Rust…...

小红的合数寻找

A-小红的合数寻找_牛客周赛 Round 79 题目描述 小红拿到了一个正整数 x&#xff0c;她希望你在 [x,2x] 区间内找到一个合数&#xff0c;你能帮帮她吗&#xff1f; 一个数为合数&#xff0c;当且仅当这个数是大于1的整数&#xff0c;并且不是质数。 输入描述 在一行上输入一…...

使用等宽等频法进行数据特征离散化

在数据分析与处理的过程中,特征离散化是一种常见的操作。通过将连续的数值型数据转换为离散类别,能够更好地处理数据,尤其是在机器学习模型中进行分类问题的建模时。离散化能够简化数据结构,减少数据噪声,并提高模型的解释性。 本文将详细介绍如何使用 pandas 库中的 cut…...

解析 Oracle 中的 ALL_SYNONYMS 和 ALL_VIEWS 视图:查找同义词与视图的基础操作

目录 前言1. ALL_SYNONYMS 视图2. ALL_VIEWS 视图3. 扩展 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 1. ALL_SYNONYMS 视图 在 Oracle 数据库中&#xff0c;同义词&#xff08;Synonym&#xff09;是对数…...

AI协助探索AI新构型的自动化创新概念

训练AI自生成输出模块化代码&#xff0c;生成元代码级别的AI功能单元代码&#xff0c;然后再由AI组织为另一个AI&#xff0c;实现AI开发AI的能力&#xff1b;用AI协助探索迭代新构型AI将会出现&#xff0c;并成为一种新的技术路线潮流。 有限结点&#xff0c;无限的连接形式&a…...

从0开始使用面对对象C语言搭建一个基于OLED的图形显示框架(OLED设备层封装)

目录 OLED设备层驱动开发 如何抽象一个OLED 完成OLED的功能 初始化OLED 清空屏幕 刷新屏幕与光标设置1 刷新屏幕与光标设置2 刷新屏幕与光标设置3 绘制一个点 反色 区域化操作 区域置位 区域反色 区域更新 区域清空 测试我们的抽象 整理一下&#xff0c;我们应…...

【Redis】Redis 经典面试题解析:深入理解 Redis 的核心概念与应用

Redis 是一个高性能的键值存储系统&#xff0c;广泛应用于缓存、消息队列、排行榜等场景。在面试中&#xff0c;Redis 是一个高频话题&#xff0c;尤其是其核心概念、数据结构、持久化机制和高可用性方案。 1. Redis 是什么&#xff1f;它的主要特点是什么&#xff1f; 答案&a…...

TensorFlow 示例摄氏度到华氏度的转换(一)

TensorFlow 实现神经网络模型来进行摄氏度到华氏度的转换&#xff0c;可以将其作为一个回归问题来处理。我们可以通过神经网络来拟合这个简单的转换公式。 1. 数据准备与预处理 2. 构建模型 3. 编译模型 4. 训练模型 5. 评估模型 6. 模型应用与预测 7. 保存与加载模型 …...

7.DP算法

DP 在C中&#xff0c;动态规划&#xff08;Dynamic Programming&#xff0c;DP&#xff09;是一种通过将复杂问题分解为重叠子问题来高效求解的算法设计范式。以下是DP算法的核心要点和实现方法&#xff1a; 一、动态规划的核心思想 重叠子问题&#xff1a;问题可分解为多个重…...

Baklib构建高效协同的基于云的内容中台解决方案

内容概要 随着云计算技术的飞速发展&#xff0c;内容管理的方式也在不断演变。企业面临着如何在数字化转型过程中高效管理和协同处理内容的新挑战。为应对这些挑战&#xff0c;引入基于云的内容中台解决方案显得尤为重要。 Baklib作为创新型解决方案提供商&#xff0c;致力于…...

在C语言多线程环境中使用互斥量

如果有十个银行账号通过不同的十条线程同时向同一个账号转账时&#xff0c;如果没有很好的机制保证十个账号依次存入&#xff0c;那么这些转账可能出问题。我们可以通过互斥量来解决。 C标准库提供了这个互斥量&#xff0c;只需要引入threads.头文件。 互斥量就像是一把锁&am…...

项目练习:重写若依后端报错cannot be cast to com.xxx.model.LoginUser

文章目录 一、情景说明二、解决办法 一、情景说明 在重写若依后端服务的过程中 使用了Redis存放LoginUser对象数据 那么&#xff0c;有存就有取 在取值的时候&#xff0c;报错 二、解决办法 方法1、在TokenService中修改如下 getLoginUser 方法中&#xff1a;LoginUser u…...

代码随想录刷题笔记

数组 二分查找 ● 704.二分查找 tips&#xff1a;两种方法&#xff0c;左闭右开和左闭右闭&#xff0c;要注意区间不变性&#xff0c;在判断mid的值时要看mid当前是否使用过 ● 35.搜索插入位置 ● 34.在排序数组中查找元素的第一个和最后一个位置 tips&#xff1a;寻找左右边…...

AI智慧社区--人脸识别

前端 人脸的采集按钮&#xff1a; 首先对于选中未认证的居民记录&#xff0c;进行人脸采集 前端的按钮 <el-form-item><el-button v-has"sys:person:info" type"info" icon"el-icon-camera" :disabled"ids.length < 0" …...

对象的实例化、内存布局与访问定位

一、创建对象的方式 二、创建对象的步骤: 一、判断对象对应的类是否加载、链接、初始化: 虚拟机遇到一条new指令&#xff0c;首先去检查这个指令的参数能否在Metaspace的常量池中定位到一个类的符号引用&#xff0c;并且检查这个符号引用代表的类是否已经被加载、解析和初始化…...

React基础知识回顾详解

以下是React从前端面试基础到进阶的系统性学习内容&#xff0c;包含核心知识点和常见面试题解析&#xff1a; 一、React基础核心 JSX原理与本质 JSX编译过程&#xff08;Babel转换&#xff09;虚拟DOM工作原理面试题&#xff1a;React为何使用className而不是class&#xff1f;…...

开发第一个安卓页面

一&#xff1a;在java.com.example.myapplication下创建MainActivity的JAVA类 里面的代码要把xml的页面名字引入 二&#xff1a;如果没有这两个&#xff0c;可以手动创建layout文件夹和activity_main.xml activity_main.xml使用来做页面的。 三、找到这个文件 把你的JAVA类引入…...

物联网 STM32【源代码形式-ESP8266透传】连接OneNet IOT从云产品开发到底层MQTT实现,APP控制 【保姆级零基础搭建】

一、MQTT介绍 MQTT&#xff08;Message Queuing Telemetry Transport&#xff0c;消息队列遥测传输协议&#xff09;是一种基于发布/订阅模式的轻量级通讯协议&#xff0c;构建于TCP/IP协议之上。它最初由IBM在1999年发布&#xff0c;主要用于在硬件性能受限和网络状况不佳的情…...

微服务-配置管理

配置管理 到目前为止我们已经解决了微服务相关的几个问题&#xff1a; 微服务远程调用微服务注册、发现微服务请求路由、负载均衡微服务登录用户信息传递 不过&#xff0c;现在依然还有几个问题需要解决&#xff1a; 网关路由在配置文件中写死了&#xff0c;如果变更必须重…...

基于SpringBoot的智慧康老疗养院管理系统的设计与实现(源码+SQL脚本+LW+部署讲解等)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…...

100.1 AI量化面试题:解释夏普比率(Sharpe Ratio)的计算方法及其在投资组合管理中的应用,并说明其局限性

目录 0. 承前1. 夏普比率的基本概念1.1 定义与计算方法1.2 实际计算示例 2. 在投资组合管理中的应用2.1 投资组合选择2.2 投资组合优化 3. 夏普比率的局限性3.1 统计假设的限制3.2 实践中的问题 4. 改进方案4.1 替代指标4.2 实践建议 5. 回答话术 0. 承前 如果想更加全面清晰地…...

LLMs之OpenAI o系列:OpenAI o3-mini的简介、安装和使用方法、案例应用之详细攻略

LLMs之OpenAI o系列&#xff1a;OpenAI o3-mini的简介、安装和使用方法、案例应用之详细攻略 目录 相关文章 LLMs之o3&#xff1a;《Deliberative Alignment: Reasoning Enables Safer Language Models》翻译与解读 LLMs之OpenAI o系列&#xff1a;OpenAI o3-mini的简介、安…...

深度解析:网站快速收录与网站安全性的关系

本文转自&#xff1a;百万收录网 原文链接&#xff1a;https://www.baiwanshoulu.com/58.html 网站快速收录与网站安全性之间存在着密切的关系。以下是对这一关系的深度解析&#xff1a; 一、网站安全性对收录的影响 搜索引擎惩罚&#xff1a; 如果一个网站存在安全隐患&am…...

【Rust自学】16.2. 使用消息传递来跨线程传递数据

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 16.2.1. 消息传递 有一种很流行而且能保证安全并发的技术&#xff08;或者叫机制&#xff09;叫做消息传递。在这种机制里&#xff0c;线…...

如何实现滑动网格的功能

文章目录 1 概念介绍2 使用方法3 示例代码 我们在上一章回中介绍了SliverList组件相关的内容&#xff0c;本章回中将介绍SliverGrid组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1 概念介绍 我们在本章回中介绍的SliverGrid组件是一种网格类组件&#xff0c;主要用来…...

使用C# 如何获取本机连接的WIFI名称[C# ---1]

前言 楼主最近在写一个WLAN上位机&#xff0c;遇到了使用C#查询SSID 的问题。CSDN上很多文章都比较老了&#xff0c;而且代码过于复杂。楼主自己想了一个使用CMD来获得SSID的方法 C#本身是没有获得WINDOWS网路信息的能力&#xff0c;必须要用系统API&#xff0c;WMI什么的&…...