C语言指针与字符串操作实验解析
任务一:数组极值求解
子任务1:通过指针返回极值
以下代码演示如何利用指针参数获取数组的最小值和最大值:
#include <stdio.h>
#define SIZE 5
void read_data(int arr[], int len);
void display(const int arr[], int len);
void get_extremes(const int arr[], int len, int *low, int *high);
int main() {
int data[SIZE];
int smallest, largest;
printf("请输入%d个整数:\n", SIZE);
read_data(data, SIZE);
printf("数组内容: ");
display(data, SIZE);
get_extremes(data, SIZE, &smallest, &largest);
printf("最小值 = %d, 最大值 = %d\n", smallest, largest);
return 0;
}
void read_data(int arr[], int len) {
for(int idx = 0; idx < len; idx++)
scanf("%d", &arr[idx]);
}
void display(const int arr[], int len) {
for(int idx = 0; idx < len; idx++)
printf("%d ", arr[idx]);
printf("\n");
}
void get_extremes(const int arr[], int len, int *low, int *high) {
*low = *high = arr[0];
for(int idx = 1; idx < len; idx++) {
if(arr[idx] < *low)
*low = arr[idx];
else if(arr[idx] > *high)
*high = arr[idx];
}
}
要点分析:
get_extremes函数接收两个指针参数,用于向调用者传递计算结果- 执行
*low = *high = arr[0]时,指针low和high分别指向主函数中的smallest和largest变量
子任务2:返回最大值的地址
#include <stdio.h>
#define SIZE 5
void read_data(int arr[], int len);
void display(const int arr[], int len);
int *locate_max(const int arr[], int len);
int main() {
int data[SIZE];
int *max_ptr;
printf("请输入%d个整数:\n", SIZE);
read_data(data, SIZE);
printf("数组内容: ");
display(data, SIZE);
max_ptr = locate_max(data, SIZE);
printf("最大值: %d\n", *max_ptr);
return 0;
}
void read_data(int arr[], int len) {
for(int idx = 0; idx < len; idx++)
scanf("%d", &arr[idx]);
}
void display(const int arr[], int len) {
for(int idx = 0; idx < len; idx++)
printf("%d ", arr[idx]);
printf("\n");
}
int *locate_max(const int arr[], int len) {
int best = 0;
for(int idx = 1; idx < len; idx++)
if(arr[idx] > arr[best])
best = idx;
return (int *)&arr[best];
}
要点分析:
- 函数返回值为指向最大元素的指针,可直接解引用获取值
- 通过地址运算
&arr[best]返回目标位置
任务二:字符数组与指针对比
子任务1:字符数组实现交换
#include <stdio.h>
#include <string.h>
#define MAX_LEN 80
int main() {
char buf1[MAX_LEN] = "C programming is fun";
char buf2[MAX_LEN] = "C programming is hard";
char temp[MAX_LEN];
printf("sizeof(buf1) = %zu\n", sizeof(buf1));
printf("strlen(buf1) = %zu\n", strlen(buf1));
printf("\n交换前:\n");
printf("buf1: %s\n", buf1);
printf("buf2: %s\n", buf2);
strcpy(temp, buf1);
strcpy(buf1, buf2);
strcpy(buf2, temp);
printf("\n交换后:\n");
printf("buf1: %s\n", buf1);
printf("buf2: %s\n", buf2);
return 0;
}
关键说明:
sizeof(buf1)返回整个数组分配的内存大小(80字节),包含未使用的空间strlen(buf1)统计到第一个'\0'为止的有效字符数- 数组定义时必须指定大小,否则编译器无法分配空间
子任务2:字符指针实现交换
#include <stdio.h>
#include <string.h>
int main() {
char *ptr1 = "C programming is fun";
char *ptr2 = "C programming is hard";
char *swap;
printf("sizeof(ptr1) = %zu\n", sizeof(ptr1));
printf("strlen(ptr1) = %zu\n", strlen(ptr1));
printf("\n交换前:\n");
printf("ptr1: %s\n", ptr1);
printf("ptr2: %s\n", ptr2);
swap = ptr1;
ptr1 = ptr2;
ptr2 = swap;
printf("\n交换后:\n");
printf("ptr1: %s\n", ptr1);
printf("ptr2: %s\n", ptr2);
return 0;
}
关键说明:
sizeof(ptr1)返回指针变量本身的大小(通常为4或8字节),而非字符串长度- 交换操作仅改变指针的指向,字符串常量本身存储位置不变
- 字符指针与字符数组在内存管理上有本质区别
任务三:二维数组的指针访问
#include <stdio.h>
int main() {
int matrix[2][4] = {{1, 9, 8, 4}, {2, 0, 4, 9}};
int row, col;
int *elem_ptr;
int (*row_ptr)[4];
printf("方式一:下标访问\n");
for(row = 0; row < 2; row++) {
for(col = 0; col < 4; col++)
printf("%d ", matrix[row][col]);
printf("\n");
}
printf("\n方式二:单指针线性遍历\n");
for(elem_ptr = &matrix[0][0], row = 0;
elem_ptr < &matrix[0][0] + 8;
elem_ptr++, row++) {
printf("%d ", *elem_ptr);
if((row + 1) % 4 == 0)
printf("\n");
}
printf("\n方式三:数组指针逐行访问\n");
for(row_ptr = matrix; row_ptr < matrix + 2; row_ptr++) {
for(col = 0; col < 4; col++)
printf("%d ", *(*row_ptr + col));
printf("\n");
}
return 0;
}
指针类型辨析:
int (*ptr)[4]:数组指针,指向包含4个整数的数组,ptr+1跳过整个数组int *ptr[4]:指针数组,包含4个整数指针的数组
任务四:字符串字符替换
#include <stdio.h>
#define CAPACITY 80
void substitute(char *text, char target, char replacement);
int main() {
char message[CAPACITY] = "Programming is difficult or not, it is a question.";
printf("原文:\n%s\n\n", message);
substitute(message, 'i', '*');
printf("替换后:\n%s\n", message);
return 0;
}
void substitute(char *text, char target, char replacement) {
while(*text != '\0') {
if(*text == target)
*text = replacement;
text++;
}
}
实现要点:
- 循环条件
*text等价于*text != '\0',利用字符串结束标志的特性 - 通过指针移动遍历整个字符串,直接修改原数组内容
任务五:字符串截断处理
#include <stdio.h>
#define CAPACITY 80
char *truncate(char *text, char delimiter);
int main() {
char input[CAPACITY];
char mark;
while(printf("输入字符串: "), gets(input) != NULL) {
printf("输入截断字符: ");
mark = getchar();
truncate(input, mark);
printf("截断结果: %s\n\n", input);
getchar();
}
return 0;
}
char *truncate(char *text, char delimiter) {
char *start = text;
while(*text) {
if(*text == delimiter) {
*text = '\0';
break;
}
text++;
}
return start;
}
任务六:身份证格式校验
#include <stdio.h>
#include <string.h>
#define TOTAL 5
int validate(char *id);
int main() {
char *candidates[TOTAL] = {
"31010120000721656X",
"3301061996X0203301",
"53010220051126571",
"510104199211197977",
"53010220051126133Y"
};
for(int i = 0; i < TOTAL; i++)
printf("%s\t%s\n", candidates[i],
validate(candidates[i]) ? "合法" : "非法");
return 0;
}
int validate(char *id) {
int len = strlen(id);
if(len != 18)
return 0;
for(int i = 0; i < 17; i++)
if(id[i] < '0' || id[i] > '9')
return 0;
char last = id[17];
if(!((last >= '0' && last <= '9') || last == 'X'))
return 0;
return 1;
}
任务七:凯撒密码编解码
#include <stdio.h>
#define CAPACITY 80
void cipher(char *text, int shift);
void decipher(char *text, int shift);
int main() {
char content[CAPACITY];
int offset;
printf("输入英文文本: ");
gets(content);
printf("输入偏移量: ");
scanf("%d", &offset);
cipher(content, offset);
printf("编码结果: %s\n", content);
decipher(content, offset);
printf("解码结果: %s\n", content);
return 0;
}
void cipher(char *text, int shift) {
while(*text) {
if(*text >= 'a' && *text <= 'z') {
*text = (*text - 'a' + shift) % 26 + 'a';
}
else if(*text >= 'A' && *text <= 'Z') {
*text = (*text - 'A' + shift) % 26 + 'A';
}
text++;
}
}
void decipher(char *text, int shift) {
while(*text) {
if(*text >= 'a' && *text <= 'z') {
*text = (*text - 'a' - shift + 26) % 26 + 'a';
}
else if(*text >= 'A' && *text <= 'Z') {
*text = (*text - 'A' - shift + 26) % 26 + 'A';
}
text++;
}
}
任务八:命令行参数排序
#include <stdio.h>
#include <string.h>
void selection_sort(char *items[], int count);
int main(int argc, char *argv[]) {
selection_sort(argv, argc);
for(int i = 1; i < argc; i++)
printf("hello, %s\n", argv[i]);
return 0;
}
void selection_sort(char *items[], int count) {
int min_idx;
char *temp;
for(int i = 1; i < count - 1; i++) {
min_idx = i;
for(int j = i + 1; j < count; j++)
if(strcmp(items[j], items[min_idx]) < 0)
min_idx = j;
if(min_idx != i) {
temp = items[i];
items[i] = items[min_idx];
items[min_idx] = temp;
}
}
}
程序特性:
- 利用
argv数组存储命令行参数,通过指针数组实现灵活排序 - 排序过程仅交换指针指向,避免大量数据移动
- 注意循环起始索引为1,跳过程序名本身