指针实战运用进阶之字符串操作
1. 上节课遗留点
#include <stdio.h>
#include <stdlib.h>
// 动态开辟之realloc
int mainT0() {
int num;
printf("请输入个数");
// 获取用户输入的值
scanf("%d", &num);
// 5个值
int * arr = (int *) malloc(sizeof(int) * num);
for (int i = 0; i < num; ++i) {
arr[i] = (i + 10001); // arr[i]的内部隐士 == *(arr+i)
}
printf("开辟的内存指针: %p\n", arr);
// 打印 内容
for (int i = 0; i < num; ++i) {
// Derry装B的打印
// &取出内存地址 *然后去值
// .....
printf("元素的值:%d, 元素的地址:%p\n",*(arr + i),(arr + i));
}
// ================================= 在堆区开辟新的空间 加长空间大小
// 新增
int new_num;
printf("请输入新增加的个数");
scanf("%d", &new_num);
// 原来的大小4 + 新增加的大小4 = 总大小 8
// void *realloc (void *前面开辟的指针, size_t总大小);
int * new_arr = (int *) realloc(arr, sizeof(int) * (num + new_num));
if (new_arr) { // new_arr != NULL 我才进if 【非0即true】
int j = num; // 4开始
for (; j < (num + new_num); j++) { // 5 6 7 8
arr[j] = (j + 10001);
}
printf("新 开辟的内存指针: %p\n", new_arr);
// 后 打印 内容
for (int i = 0; i < (num + new_num); ++i) {
printf("新 元素的值:%d, 元素的地址:%p\n",
*(arr + i),
(arr + i)
);
}
}
// 我已经释放
/*free(new_arr);
new_arr = NULL;*/
// 1000行代码
// 。。。
// 重复释放/重复free VS会奔溃, CLion会优化(发现不奔溃) [错误的写法]
/*free(new_arr);
new_arr = NULL;*/
// 必须释放【规则】
/*if (arr) {
free(arr); // 如果不赋值给NULL,就是悬空指针了
arr = NULL;
}*/
/*if (new_arr) {
free(new_arr); // 如果不赋值给NULL,就是悬空指针了
new_arr = NULL;
}*/
// TODO ========================== 下面代码对我们上节课 遗留点 完成 末尾工作了
if (new_arr) { // new_arr != NULL 进去if, 重新开辟的堆空间是成功的
free(new_arr);
new_arr = NULL;
arr = NULL; // 他还在指向那块空间,为了不出现悬空指针,指向NULL的空间
} else { // 重新开辟的堆空间是失败的
free(arr);
arr = NULL;
}
// 画图:内存的走向 1
return 0;
}
2. 字符串两种形式
#include <stdio.h>
int mainT2(){
char str[] = {'D', 'e', 'r', 'r', 'y', '\0'};
str[2] = 'z'; // 这里能修改?
printf("第一种方式:%s\n", str); // printf 必须遇到 \0 才结束
char * str2 = "Derry"; // 隐士 Derry+\0
//str2[2] = 'z'; 这样写是错误的,会奔溃,不允许访问,为什么 画图 原理图
printf("第二种方式:%s\n", str2);
return 0;
}
3. 指针挪动获取字符串信息(手写API)
// 3.指针挪动获取字符串信息
#include <stdio.h>
// 获取长度
/*int getLen(char * string) {
int count = 0;
// *string != '\0' 我就一直循环
while (*string) {
string ++;
count++;
}
return count;
}
int mainT3() {
char string[] = {'A', 'B', 'C', 'D', '0', '\0'}; // printf方法能够停下来,不要打印系统值
int r = getLen(string);
printf("长度是:%d\n",r);
return 0;
}*/
// C/C++编译器,数组作为参数传递,会把数组优化成指针(为了高效率)
//void getLen(int intarr[]) {
//数组作为参数传递,就不能这样写了
//sizeof(intarr)28/sizeof(int)4=7
//int len = sizeof(intarr)/sizeof(int);
//printf("getLen len长度是:%d\n", len);
//}
// 模仿了 strLen函数
void getLen(int * resultLen, int intarr[]) {
//手动计算长度
int count = 0;
while (*intarr) {
intarr++;
count++;
}
*resultLen = count;
}
void doEngine(int len) {}
int mainT3(){
// 数组中加‘\0’的原因是让printf方法能够停下来,不要打印系统值
// char string[] = {'A', 'B', 'C', 'D', '0', '\0'};
// 0, \0其他函数for其他调用判断的时候.这个有冲突【int类型数组】
int intarr[] = {1, 2, 3, 4, 5, 6, 7, '\0'};
//int类型使用这种方式【第一种方式】
//sizeof(intarr)28 / sizeof(int)4 = 7;
int len = sizeof(intarr) / sizeof(int);
printf("len长度是:%d\n", len);
int result; //&取出result遍历的地址值给函数
getLen(&result, intarr);
printf("getLen len长度是:%d\n", result);
// strLen API 的用法太简单 【第二种方式】 尝试
// 真实函数直接调用,可以这样,传递长度
doEngine(len);
return 0;
}
4. 字符串的比较
// 字符串查找,包含,拼接。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int mainT5() {
char * text = "name is Derry";
char * subtext = "D";
char * pop = strstr(text, subtext);
// 怎么去 字符串查找
if (pop) { // 非NULL,就进入if,就查找到了
printf("查找到了,pop的值是:%s\n", pop);
} else {
printf("没有查找到,subtext的值是:%s\n", subtext);
}
// 包含了D吗
if (pop) {
printf("包含了\n");
} else {
printf("没有包含\n");
}
// printf("pop地址%p, text地址:%p,\n", pop, text);
// 求取位置? 数组是一块连续的内存空间,没有断层,所以可以-
int index = pop - text; // pop="Derry" - text"name is Derry"
printf("%s第一次出现的位置是:%d\n", subtext, index); // 我的D在第8个位置
// 指针是可以:++ -- += -=
// 拼接 ========================
char destination[25]; // 容器 25的大小 已经写死了
char * blank = "--到--", *CPP="C++", *Java= "Java";
strcpy(destination, CPP); // 先Copy到数组里面去
strcat(destination, blank); // 然后再拼接
strcat(destination, Java); // 然后再拼接
printf("拼接后的结果:%s\n", destination); // C++--到--Java
return 0;
}
5. 字符串查找,包含,拼接
// 字符串查找,包含,拼接。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int mainT5() {
char * text = "name is Derry";
char * subtext = "D";
char * pop = strstr(text, subtext);
// 怎么去 字符串查找
if (pop) { // 非NULL,就进入if,就查找到了
printf("查找到了,pop的值是:%s\n", pop);
} else {
printf("没有查找到,subtext的值是:%s\n", subtext);
}
// 包含了D吗
if (pop) {
printf("包含了\n");
} else {
printf("没有包含\n");
}
// printf("pop地址%p, text地址:%p,\n", pop, text);
// 求取位置? 数组是一块连续的内存空间,没有断层,所以可以-
int index = pop - text; // pop="Derry" - text"name is Derry"
printf("%s第一次出现的位置是:%d\n", subtext, index); // 我的D在第8个位置
// 指针是可以:++ -- += -=
// 拼接 ========================
char destination[25]; // 容器 25的大小 已经写死了
char * blank = "--到--", *CPP="C++", *Java= "Java";
strcpy(destination, CPP); // 先Copy到数组里面去
strcat(destination, blank); // 然后再拼接
strcat(destination, Java); // 然后再拼接
printf("拼接后的结果:%s\n", destination); // C++--到--Java
return 0;
}
6. 大小写转换(手写API)
// 大小写转换(手写API)
#include <stdio.h>
#include <ctype.h>
// 指针的理解
void lower(char * dest, char * name) {
char * temp = name; // 临时指针,你只能操作临时指针,不能破坏name指针
while (*temp) {
*dest = tolower(*temp);
temp ++; // 挪动指针位置 ++
dest ++; // 挪动指针位置 ++ 目的是为了 挪动一个存储一个 挪动一个存储一个 ...
}
// printf '\0'
*dest = '\0'; // 避免printf打印系统值
printf("不能破坏 name:%s\n", name); // temp的好处就是,不会破坏name
}
// 全部变成小写 derry
int mainT6() {
char * name = "DerrY"; // 隐士 DerrY+\0
// 先定义结果
char dest[20];
lower(dest, name);
printf("小写转换后的结构是:%s\n", dest);
// 这样-不成功
/*char * a = "ABCDEFG";
char * b = "AB";
int r = b - a;
printf("r:%d\n", r);*/
// 作业:
/*char * str = "Derry is";
char * result;
函数(&result, str, 2, 5);
printf("%s\n", result); 最终输出:rry*/
return 0;
}