C语言中数组与指针的综合运用
C语言中数组与指针是基础且重要的概念,它们在实际编程中经常结合使用。本文通过几个典型示例演示数组元素的访问方式、指针运算、字符串处理以及函数参数传递。
一、数组元素与指针的基本操作
定义整型数组并实现输入、输出、查找最值。本例中函数通过指针参数返回最小值和最大值。
#include <stdio.h>
#define SIZE 5
void read_array(int arr[], int n);
void print_array(int arr[], int n);
void find_min_max(int arr[], int n, int *min, int *max);
int main() {
int data[SIZE];
int low, high;
printf("输入%d个整数:\n", SIZE);
read_array(data, SIZE);
printf("数组内容:\n");
print_array(data, SIZE);
find_min_max(data, SIZE, &low, &high);
printf("最小值 = %d, 最大值 = %d\n", low, high);
return 0;
}
void read_array(int arr[], int n) {
for (int i = 0; i < n; ++i)
scanf("%d", &arr[i]);
}
void print_array(int arr[], int n) {
for (int i = 0; i < n; ++i)
printf("%d ", arr[i]);
printf("\n");
}
void find_min_max(int arr[], int n, int *min, int *max) {
*min = *max = arr[0];
for (int i = 1; i < n; ++i) {
if (arr[i] < *min) *min = arr[i];
if (arr[i] > *max) *max = arr[i];
}
}
二、返回指针的函数
改写上一个例子,使函数返回最大值元素的地址。
#include <stdio.h>
#define N 5
void read(int a[], int n);
void write(int a[], int n);
int *max_addr(int a[], int n);
int main() {
int arr[N];
int *pmax;
printf("录入%d个数据:\n", N);
read(arr, N);
printf("数据: \n");
write(arr, N);
pmax = max_addr(arr, N);
printf("最大值 = %d\n", *pmax);
return 0;
}
void read(int a[], int n) {
for (int i = 0; i < n; ++i)
scanf("%d", &a[i]);
}
void write(int a[], int n) {
for (int i = 0; i < n; ++i)
printf("%d ", a[i]);
printf("\n");
}
int *max_addr(int a[], int n) {
int max_idx = 0;
for (int i = 1; i < n; ++i)
if (a[i] > a[max_idx])
max_idx = i;
return &a[max_idx];
}
三、字符串数组与指针的交换
演示字符数组与字符指针在存储和交换时的区别。
#include <stdio.h>
#include <string.h>
int main() {
char s1[80] = "Learning makes me happy";
char s2[80] = "Learning makes me sleepy";
char tmp[80];
printf("sizeof(s1) = %lu, strlen(s1) = %lu\n", sizeof(s1), strlen(s1));
printf("交换前:\ns1: %s\ns2: %s\n", s1, s2);
strcpy(tmp, s1);
strcpy(s1, s2);
strcpy(s2, tmp);
printf("交换后:\ns1: %s\ns2: %s\n", s1, s2);
// 对比指针版本
char *p1 = "Learning makes me happy";
char *p2 = "Learning makes me sleepy";
char *ptmp;
printf("\n指针版:\n");
printf("sizeof(p1) = %lu, strlen(p1) = %lu\n", sizeof(p1), strlen(p1));
printf("交换前:p1: %s, p2: %s\n", p1, p2);
ptmp = p1; p1 = p2; p2 = ptmp;
printf("交换后:p1: %s, p2: %s\n", p1, p2);
return 0;
}
输出说明:sizeof(s1)返回数组总字节(包括'\0'),strlen仅计算有效字符;指针版sizeof(p1)返回指针本身大小,交换仅交换地址,原字符串不变。
四、二维数组与指针的多种遍历方式
定义一个2x4的二维数组,分别用下标、元素指针和行指针访问。
#include <stdio.h>
int main() {
int matrix[2][4] = {{1,9,8,4}, {2,0,4,9}};
int i, j;
int *p1; // 元素指针
int (*p2)[4]; // 行指针,指向含4个int的数组
// 下标法
printf("下标法:\n");
for (i = 0; i < 2; ++i) {
for (j = 0; j < 4; ++j)
printf("%d ", matrix[i][j]);
printf("\n");
}
// 元素指针
printf("元素指针:\n");
for (p1 = &matrix[0][0], i = 0; p1 < &matrix[0][0] + 8; ++p1, ++i) {
printf("%d ", *p1);
if ((i+1) % 4 == 0) printf("\n");
}
// 行指针
printf("行指针:\n");
for (p2 = matrix; p2 < matrix + 2; ++p2) {
for (j = 0; j < 4; ++j)
printf("%d ", *(*p2 + j));
printf("\n");
}
return 0;
}
注意:int (*ptr)[4]是行指针,自增跳过整行;int *ptr[4]是指针数组。
五、字符串替换函数
将字符串中指定字符替换为另一个字符。
#include <stdio.h>
#define SIZE 80
void replace(char *str, char old, char new) {
while (*str) {
if (*str == old)
*str = new;
str++;
}
}
int main() {
char text[SIZE] = "Programming is difficult or not, it is a question.";
printf("原始: %s\n", text);
replace(text, 'i', '*');
printf("替换后: %s\n", text);
return 0;
}
六、字符串截断函数
从第一个指定字符处将字符串截断(设为'\0')。
#include <stdio.h>
#define N 80
char *trunc_str(char *str, char ch) {
char *p = str;
while (*p != '\0' && *p != ch)
p++;
if (*p == ch)
*p = '\0';
return str;
}
int main() {
char buf[N];
char delimiter;
while (printf("输入字符串: "), gets(buf) != NULL) {
printf("输入截断字符: ");
delimiter = getchar();
getchar(); // 吸收换行
trunc_str(buf, delimiter);
printf("结果: %s\n\n", buf);
}
return 0;
}
七、身份证号校验
检查字符串是否为合法18位身份证号(前17位数字,末位可为数字或大写X)。
#include <stdio.h>
#include <string.h>
int valid_id(const char *id) {
int len = strlen(id);
if (len != 18) return 0;
for (int i = 0; i < len; ++i) {
if (id[i] < '0' || id[i] > '9') {
if (i != 17 || id[i] != 'X')
return 0;
}
}
return 1;
}
int main() {
const char *ids[] = {"31010120000721656X",
"3301061996X0203301",
"53010220051126571",
"510104199211197977",
"53010220051126133Y"};
for (int i = 0; i < 5; ++i)
printf("%s\t%s\n", ids[i], valid_id(ids[i]) ? "True" : "False");
return 0;
}
八、凯撒加密与解密
对英文字母进行循环移位,编码用后移n位,解码用前移n位。
#include <stdio.h>
#define N 80
void encode(char *str, int n) {
while (*str) {
if (*str >= 'a' && *str <= 'z')
*str = (*str - 'a' + n) % 26 + 'a';
else if (*str >= 'A' && *str <= 'Z')
*str = (*str - 'A' + n) % 26 + 'A';
str++;
}
}
void decode(char *str, int n) {
while (*str) {
if (*str >= 'a' && *str <= 'z')
*str = (*str - 'a' - n + 26) % 26 + 'a';
else if (*str >= 'A' && *str <= 'Z')
*str = (*str - 'A' - n + 26) % 26 + 'A';
str++;
}
}
int main() {
char text[N];
int shift;
printf("输入英文文本: ");
gets(text);
printf("输入移位量: ");
scanf("%d", &shift);
encode(text, shift);
printf("编码后: %s\n", text);
decode(text, shift);
printf("解码后: %s\n", text);
return 0;
}
九、命令行参数排序与输出
对命令行输入的字符串数组按字典序排序,并输出带"hello, "前缀的结果。
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
// 冒泡排序
for (int i = 1; i < argc - 1; ++i) {
for (int j = 1; j < argc - i; ++j) {
if (strcmp(argv[j], argv[j+1]) > 0) {
char *temp = argv[j];
argv[j] = argv[j+1];
argv[j+1] = temp;
}
}
}
for (int i = 1; i < argc; ++i)
printf("hello, %s\n", argv[i]);
return 0;
}