在C语言中,数组名就是数组首元素的地址,它是一个常量。所以我们可以使用指针来操作数组
指针遍历数组
void iterateArray() {
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 指针p指向arr[0]的地址
int *p = arr; // 等同于:int *p = &arr[0]
int len = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < len; i++) {
printf("%d\n", p[i]);
}
}
从上图可以看出,每个元素的地址相差4个字节,所以p指针加一个int类型的大小就是下一个元素的地址。
void iterateArray2() {
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 指针p指向arr[0]的地址
int *p = arr; // 等同于:int *p = &arr[0]
int len = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < len; i++) {
// p + i 表示地址变成了:p + i * sizeof(int)
printf("地址为:%p\n", p + i);
printf("地址对应的值:%d\n", *(p + i));
}
}
指针++与指针+n的区别
指针+n只是把当前的地址变成了某个元素的地址,指针并没有移动;而指针++或指针--是把指针向右或者向左进行移动。
void pointerOperate() {
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 指针p指向arr[0]的地址
int *p = arr; // 等同于:int *p = &arr[0]
// 将数组第三个元素的值改为300
*(p + 2) = 300; // {1, 2, 300, 4, 5, 6, 7, 8, 9, 10}
// 将p指向数组第二个元素的地址,并将值改为200
p++;
*p = 200; // {1, 200, 300, 4, 5, 6, 7, 8, 9, 10}
// 以当前p所在地址,改变内存地址为 2 * sizeof(arr[0])的值为400
*(p + 2) = 400; // {1, 200, 300, 400, 5, 6, 7, 8, 9, 10}
// 将p指向数组第9个元素的地址,将元素值改为900
p = &arr[8];
*p = 900; // {1, 200, 300, 400, 5, 6, 7, 8, 900, 10}
// 将p指向数组第8个元素的地址,并将元素值改为800
p--;
*p = 800; // {1, 200, 300, 400, 5, 6, 7, 800, 900, 10}
// 将p指向数组第1个元素的地址,并将元素值改为101
p = &arr[0];
*p += 100; // {101, 200, 300, 400, 5, 6, 7, 800, 900, 10}
// 野指针,不允许操作未知空间的值
// p = 100;
// *p = 100;
int len = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < len; i++) {
printf("%d\n", arr[i]);
}
}
指针数组与多级指针
指针数组,顾名思义,就是数组元素都是地址。
int a = 1, b = 2, c = 3;
int *arr[] = {&a, &b, &c};
*arr[0] = 4;
printf("%d\n", a);
当数组元素为字符串时,也就变成了二级指针。
char *strArr[] = {"Tom", "Lucy", "Lily"};
// 数组的元素是字符串,而字符串是一个字符数组
char *p = strArr[0];
// 用一个二级指针指向一级指针
char **pp = strArr;
printf("%X\n", **pp);
多级指针
在内存中,每一个变量都有其对应的地址,指向这个地址的就是一个指针变量。既然指针变量也是一个变量,那么它也有其自己的地址,那么指向这个提针变量地址的称为多级指针。
int d = 4;
int *p1 = &d;
int **p2 = &p1;
int ***p3 = &p2;
int ****p4 = &p3;
// n级指针的关系
*p4 = p3 = &p2;
**p4 = *p3 = p2 = &p1;
***p4 = **p3 = *p2 = p1 = &d;
****p4 = ***p3 = **p2 = *p1 = d;
指针练习
- 在字符串中查找字符
char *charInStr(char *src, char target) {
while (*src) {
if (*src == target) {
return src;
}
src++;
}
return NULL;
}
- 字符串反转
用两个指针变量,一个指向头,一个指向尾,头指针++,尾指针--。
void strReverse(char *str) {
char *head = str;
char *tail = &str[strlen(str) - 1];
while (head < tail) {
char temp = *head;
*head = *tail;
*tail = temp;
head++;
tail--;
}
}
- 去除字符串首尾空字符
char *trimStrBlank(char *str) {
char *head = str;
char *tail = str + strlen(str) - 1;
while (*head == ' ' && head < tail) {
head++;
}
while (*tail == ' ' && tail > head) {
tail--;
}
// 去掉空字符后需加上字符串结束标志
*(tail + 1) = '\0';
return head;
}
- 在字符串中查找字符串
遍历源字符串,将源字符串中的每一个字符与目标字符进行一一比对。
char *strInStr2(char *src, char *target) {
char *res = NULL;
char *temp = target;
while (*src) {
// 记录src遍历到的位置
res = src;
// 相等情况
while (*src && *temp == *src) {
temp++;
src++;
}
if (!*temp) {
// 说明target字符全部匹配成功
return res;
} else {
// 重置temp,进行下一轮比较
temp = target;
}
src++;
}
return NULL;
}
- 字符串拼接
void strConcat(char *src, char *target) {
while (*src) {
src++;
}
while (*target) {
*src = *target;
src++;
target++;
}
// src已经++到最后一个位置了,
// 所以添加字符串结束标志时不需要+1了
*src = '\0';
}
- 字符串排序
void strSort(char **arr, int len) {
for (int i = 0; i < len - 1; i++) {
for (int j = 0; j < len - i - 1; j++) {
if (**(arr + j) > **(arr + j + 1)) {
char *temp = *(arr + j);
*(arr + j) = *(arr + j + 1);
*(arr + j + 1) = temp;
}
}
}
}
int main() {
// 这是一个指针数组
char *strArr[] = {"dog", "cat", "boy", "ago"};
int len = sizeof(strArr) / sizeof(strArr[0]);
// 所以这个函数的第一个参数是一个二级指针
strSort(strArr, len);
for (int i = 0; i < len; ++i) {
printf("%s\n", strArr[i]); // ago boy cat dog
}
return EXIT_SUCCESS;
}