04.字符串常见操作和指针练习
知识点:
1.字符串定义
字符串以 \0
结尾,动态开辟内存的时候也需要多考虑一位
定义方式有两种:
char str[] = {'E','a','s','t','r','i','s','e','\0'};
: 可以修改const char *str1 = "Eastrise";
:不能修改,字符串常量存放再全局的const内存区
int main(){
// 第一种 字符串数组
char str[] = {'E','a','s','t','r','i','s','e','\0'};
str[2] = 'y';
printf("%s\n",str); // 字符串结尾必须是 '\0',开辟内存也需要多开辟一个
// 第二种 不加 const 会警告:deprecated conversion from string constant to 'char*'
// 原因:
// "Eastrise"是字符串常量, 内存分配在全局的const内存区
// char * 声明了一个指针,而这个指针指向的是全局的const内存区,const内存区当然不会让你想改就改的。所以,如果你一定要写这块内存的话,那就是一个非常严重的内存错误。
const char *str1 = "Eastrise";
// str1[2] = 'y';
printf("%s\n",str1);
// 两种定义的区别:一个能修改,一个不能修改
}
2.字符串长度获取
-
strlen(name)
-
通过sizeof 进行计算(不好使),不对
const char str[] = {'E','a','s','t','r','i','s','e','\0','i','s'}; // 怎么获取长度?有一种方式计算(不好使) printf("length is %d",sizeof(str)/sizeof(char)); // 打印出来 11,实际结果应该是 8
-
写一个方法读取字符串的长度
int strlen_(char *str){ // 怎么获取字符串的长度? 不断读取字符,判断末尾 '\0' int len = 0; while (*str != '\0') { len++; str++; } return len; }
3.字符串与基本数据类型的转换
atoi(num_str);
//str 转 int
如果不能转换就是 0 ,后面如果有其他不是数字的就会被剔除 12xxx -> 12atof(num_str);
//str 转 float
// 如果不能转换返回的是默认值 0.000000strtod(num_str, NULL);
//str 转 double
// 如果不能转换返回的是默认值 0.000000
int main(){
const char* num1 = "1"; // -> int float double
const char* num_str1 = "12.0xxx";
int number1 = atoi(num_str1); // 如果不能转换就是 0 ,后面如果有其他不适数字的就会被剔除 12xxx -> 12
printf("number1 is %d\n",number1);
const char* num_str2 = "12.5f";
float number2 = atof(num_str2); // 如果不能转换返回的是默认值 0.0000
printf("number2 is %f\n",number2);
const char *num_str3 = "12.5xx";
double number3 = strtod(num_str3,NULL);// 如果不能转换就是 0.000 ,后面如果有其他不适数字的就会被剔除 12.5xxx -> 12.5000
printf("number3 is %lf\n",number3);
getchar();
}
打印结果:
number1 is 12
number2 is 12.500000
number3 is 12.500000
4.字符串的比较
int rc = strcmp(str1, str2);
//区分大小写
比较,rc == 0代表相等,rc > 0 str1 比 str2 大int rc = strcmpi(str1, str2);
//不区分大小写
比较,rc == 0代表相等,反之不相等int rc = strncmp(str1, str2,7);
//区分大小写
比较, count 代表的是比较字符串前几个是否相等int rc = strnicmp(str1, str2,7);
//不区分大小写
比较, count 代表的是比较字符串前几个是否相等
int main(){
const char* str1 = "Eastrise";
const char* str2 = "eastrise";
// 大于小于等于
// int rc = strcmp(str1,str2); // 区分大小写比较
// int rc = _strcmpi(str1,str2); // 不区分大小写比较 c strcmpi c++ _strcmpi , android ndk strcasecmp;
// 比较前几个
// int rc = strncmp(str1,str2,7); // count 达标的是比较字符串前几个是否相等
int rc = _strnicmp(str1,str2,6); // 不区分大小写的比较
if(rc == 0) {
printf("相等");
}else{
printf("不相等");
}
getchar();
}
5.字符串查找,包含
-
char* pos = strstr(str, substr);
// 返回的是字符串
第一次出现的位置(位置指针), 如果没有找到返回的是空获取位置:
int position = pos - str;
-
char* pos = strchr(name,'n');
// 返回的是字符
第一次出现的位置(位置指针), 如果没有找到返回的是空
int main() {
const char *str = "name not Eastrise";
const char *substr = "E";
char *pos = strstr(str, substr); // 返回的是字符串第一次出现的位置(位置指针),如果没有找到返回的是空
printf("%s\n", pos); // Eastrise;
// 求一下位置 int 怎么办? strstr
int position = pos - str;
printf("第一次出现的位置是:%d\n", position);
// 包含? pos 是不是空就可以了
if (pos)
printf("%s", "包含");
else
printf("%s", "不包含");
getchar();
}
打印结果:
Eastrise
第一次出现的位置是:9
包含
6.字符串复制和拼接
strcpy(dst, src);
// 复制strcat(dst,src);
// 拼接
int main(){
//strcopy; copy进来
const char* str = "eastrise";
const char* str1 = " is";
// char* str1 = "is";
char cpy[strlen(str)+strlen(str1)];
// str 会 copy 到 cpy 里面
strcpy(cpy,str);
printf("%s\n",cpy);
//拼接
strcat(cpy,str1);
printf("%s",cpy);
getchar();
}
打印结果:
eastrise
eastrise is
7.手写字符串截取
// 截取
char* substr(const char* str,int start ,int end){
// 开辟一个字符串去存储我们的数据,开辟多大计算
// char sub[end -start];
int len = end - start;
if (len == 0) {
return nullptr;
}
char* sub = (char*)malloc(sizeof(char)*(len+1));// 记得+1,因为还有一个\0,在 NDK 一般会采用静态的数组存储 char sub[len]
// malloc 一定要 free
// 遍历赋值
for(int i = 0; i< len; i++){
sub[i] = str[start+i];
}
// 标记字符串结尾,否则 print 无法判断结尾
sub[len] = '\0';
printf("%p\n",sub);
// free(sub);
return sub;
}
// 字符串的截取
int main(){
const char* str = "Eastrise is";
// 截取第三个位置到第五个位置 3,5
char* sub = substr(str,0,5);
printf("%p\n",sub);
printf("%s",sub);
// 一定要free ,因为你的 substr 有动态开辟内存,但是真正开发中并不会这么做,自己的方法尽量要自己处理好内存
free(sub);
getchar();
}
打印结果:
0000000000B61440
0000000000B61440
Eastr
8.手写字符串小写转换
字符大小写转换
tolower(ch);
// A->atoupper(ch);
// a->A
#include <ctype.h>
// dest 用来存放结果, 大小自己指定
// source 需要转换的字符串
void lower(char* dest,const char* source){
while (*source != '\0'){
// 拿当前字符
char ch = *source;
// 转换完成后赋值给 dest
*dest = tolower(ch); // a->a A->a
source++;
dest++;
}
// 标记字符串结尾
*dest = '\0';
}
void upper(char* dest,const char* source){
while (*source != '\0'){
char ch = *source;
*dest = toupper(ch);
source ++;
dest ++;
}
*dest = '\0';
}
9. 手写字符串的替换
char *substr(const char *str, int start, int end) {
// 开辟一个字符串去存储我们的数据,开辟多大计算
// char sub[end -start];
int len = end - start;
if (len == 0) {
return nullptr;
}
char *sub = (char *) malloc(sizeof(char) * (len + 1));// 记得+1,因为还有一个\0,在 NDK 一般会采用静态的数组存储 char sub[len]
// malloc 一定要 free
// 遍历赋值
for (int i = 0; i < len; i++) {
sub[i] = str[start + i];
}
// 标记字符串结尾,否则 print 无法判断结尾
sub[len] = '\0';
printf("%p\n", sub);
// free(sub);
return sub;
}
char *str_replace(const char *str, const char *src, const char *dst) {
char *pos = strstr(str, src);
if (!pos)
return const_cast<char *>(str);
// 1. 计算新的数组大小
char result[strlen(str) - strlen(src) + strlen(dst)];
// 截取替换
int start_position = pos - str;
char *start = substr(str, 0, start_position);
char *end = substr(str, start_position + strlen(src), strlen(str));
// 拼接
if (start){
strcpy(result, start);
strcat(result, dst);
free(start);
if (end){
strcat(result, end);
free(end);
}
}else{
strcpy(result, dst);
if (end){
strcat(result, end);
free(end);
}
}
return str_replace(result, src, dst);
}
// 字符串替换
int main() {
char *str = str_replace("aabbaabbfffaa", "aa", "ccc");
printf("%s", str);
getchar();
}
打印结果:
00000000006D1840
00000000006D1860
00000000006D1880
00000000006D18A0
cccbbcccbbfffccc