C语言复习:字符串和一级指针
字符串基本操作
字符数组初始化方法
int main() { //1 {}号法 初始化列表 //数组初始化有2种方法 默认元素个数、指定元素个数 char buf1[] = { 'a', 'b', 'c', 'd', 'e' }; //若没有指定长度,默认数组长度即为参数个数 //若指定长度,指定长度小于参数个数→报错;buf长度多于初始化个数,会自动在后面补充零。 char buf2[6] = { 'a', 'b', 'c', 'd', 'e' }; char buf3[6] = { 'a', 'b', 'c', 'd', 'e' }; //char buf4[5] = {'a', 'b', 'c', 'd', 'e'}; printf("buf3:%s", buf3); system("pause"); } |
//在C语言中使用字符数组来模拟字符串 //C语言中的字符串是以'\0'结束的字符数组 //C语言中的字符串可以分配于栈空间,堆空间或者只读存储区 int main12() { //1 用字符串来初始化数组 char buf2[] = { 'a', 'b','c','d','\0' }; //2 字符串常量初始化一个字符数组 char buf3[] = { "abcde" }; char buf4[] = "abcde"; char buf5[100] = "abcde";
printf(" strlen(buf5) :%d \n", strlen(buf5)); printf(" sizeof(buf4) :%d \n", sizeof(buf5)); printf(" sizeof(buf4) :%d \n", sizeof(buf4)); } |
sizeof与strlen的区别: strlen()求字符串的长度,注意字符串的长度不包含\0 sizeof(类型)字符串类型的大小,包括\0; |
数组法和指针法操作字符串
03 字符串操作:数组法,下标法 字符数组名,是个指针,是个常量指针; 字符数组名,代表字符数组首元素的地址,不代表整个数组的。 如果代表这个数组,那需要数组数据类型的知识! |
//字符串操作方法 数组下标法 指针法 int main() { int i = 0; char buf[100] = "abcde"; char *p = NULL;
//下标法 for (i = 0; i<100; i++) { printf("%c", buf5[i]); } printf("\n");
//指针法1 for (i = 0; i<100; i++) { printf("%c", *(buf5 + i)); } //buf5是个指针,是个常量指针
//指针法2 printf("\n"); p = buf5; for (i = 0; i<100; i++) { printf("%c", *(p + i)); } //buf5是个指针,是个常量指针 } |
推演过程为:i变0+i, 去[]号加*号 //其实本质:指针*p间接寻址,操作内存; //[]:其实是编译器为我们做了*p操作而已 |
3.2字符串做函数参数
深入理解指针的关键是什么? 注意 指针和数组的巨大区别 char *p = "abcdefg"; char *buf = "abcdefg"; 一维字符串内存模型:两种 |
void copy_str01(char *from, char *to) { for (; *from != '\0'; from++, to++) { *to = *from; } *to = '\0'; }
void copy_str02(char *from, char *to) { while (*from != '\0') { *to++ = *from++; } *to = '\0'; }
void copy_str03(char *from, char *to) { while ((*to = *from) != '\0')//不用在后面添加'\0'因为\0已经复制过去了;复制\0之后才判断不满足条件从而退出循环 { to++; from++; } }
void copy_str04(char *from, char *to) { while ((*to++ = *from++) != '\0') { ; } }
int copy_str05_good(const char *from, char *to)//就这个最好,因为考虑到了指针本身为空(野指针)的情况 { if (from == NULL || to == NULL) { printf("func copy_str05_good() err. (from==NULL || to==NULL)\n"); return -1; }
while ((*to++ = *from++) != '\0') { ; } return 0; } |
典型错误知多少 |
char *str_cnct(char *x, char* y) /*简化算法*/ { char str3[80]; char *z = str3; /*指针z指向数组str3*/ while (*z++ = *x++); z--; /*去掉串尾结束标志*/ while (*z++ = *y++); z = str3; /*将str3地址赋给指针变量z*/ return(z); } 语法没问题,但是逻辑有错,错在没有规避"下级的数据不能用于上级"的错误。 |
修改字符常量结果会如何 char *p = "abcdefg"; Modify p[1] = '1'; 段错误! |
04字符串操作易错 |
//你往哪里输入数据 int main() { char buf[2000]; char *p = NULL; p = buf; printf("\n请输入一个字符串:"); scanf("%s", p);//野指针 printf("%s", p);
getchar(); getchar(); return 0; } |
3.3库函数api
快速的上手api是一种能力! |
建立正确的程序运行示意图,(内存四区及函数调用堆栈图)是根本保障!! |
#include <stdio.h> #include <string.h>
int main1() { char buf1[100]; char buf2[200]; strcpy(buf1, "111");//将后面的字符串复制到前面的缓存中 printf("%s", strcat(buf1, "222")); getchar(); return 0; }
int main2() { char *string1 = "1234567890"; char *string2 = "747DC8"; int length; //在字符str1中查找,与str2中任意字符有公共交集的个数 length = strcspn(string1, string2); printf("Character where strings intersect is at position %d\n", length);//len=3
getchar(); return 0; }
//strnset函数: 将字符串的前n个字符设置为指定字符 //测试程序修改如下 int main3() { char string[] = "abcdefghijklmnopqrstuvwxyz"; char letter = 'x'; printf("string before strnset: %s\n", string); strnset(string, letter, 13); printf("string after strnset: %s\n", string); getchar(); return 0; }
int main4() { char *string1 = "abcdefghijklmnopqrstuvwxyz"; char *string2 = "onm"; char *ptr; ptr = strpbrk(string1, string2); //strpbrk()函数检索两个字符串中首个相同字符的位置 if (ptr) printf("strpbrk found first character: %c\n", *ptr); else printf("strpbrk didn't find character in set\n"); getchar(); return 0;
}
int main5() { char input[16] = "abc,d"; char *p; /* strtok places a NULL terminator in front of the token, if found */ p = strtok(input, ","); if (p) printf("%s\n", p); /* A second call to strtok using a NULL as the first parameter returns a pointer to the character following the token */ p = strtok(NULL, ","); if (p) printf("%s\n", p);
getchar(); return 0; }
//典型的状态函数 int main() { char str[] = "now # is the time for all # good men to come to the # aid of their country"; //char delims[] = "#"; char *delims = "#"; char *result = NULL; result = strtok(str, delims); while (result != NULL) { printf("result is \"%s\"\n", result); result = strtok(NULL, delims); } printf("----------==========----------\n"); printf("%s", str);
getchar();
return 0; } |
3.4字符串相关一级指针内存模型
void main()
{
char buf[20]= "aaaa";
char buf2[] = "bbbb";
char *p1 = "111111";
char *p2 = malloc(100); strcpy(p2, "3333");
system("pause");
return ;
}
字符串反转模型
3.6一级指针(char *)易错模型分析
char *(字符串)做函数参数出错模型分析
建立一个思想:是主调函数分配内存,还是被调用函数分配内存; |
void copy_str21(char *from, char *to) {
if (*NULL = '\0' || *to!='\0') { Printf("func copy_str21() err\n"); return; }
for (; *from!='\0'; from++, to++) { *to = *from; } *to = '\0'; } //字符串逆序 int main() { //char p[1024] ={0}; char *p ={0}; p = NULL;
char to[100]; copy_str21(p, to); |
C语言中没有你不知道的,只有你不会调 Java语言中没有你不会调的,只有你不知道 |
不断修改内存指针变量 |
02越界
越界 语法级别的越界 |
char buf[3] = "abc"; |
03不断修改指针变量的值
越界 |
void copy_str_err(char *from, char *to) { for (; *from != '\0'; from++, to++) { *to = *from; } *to = '\0'; printf("to:%s", to); printf("from:%s", from); } |
04你向外面传递什么
1、临时str3内存空间 |
// char *str_cnct(x,y) /*简化算法*/ // char *x,*y; char *str_cnct(char *x, char* y) /*简化算法*/ { char str3[80]; char *z = str3; /*指针z指向数组str3*/ while (*z++ = *x++); z--; /*去掉串尾结束标志*/ while (*z++ = *y++); z = str3; /*将str3地址赋给指针变量z*/ return(z); } 2、经验要学习 while (*z++ = *x++); z--; /*去掉串尾结束标志*/ |
char *str_cnct(char *x, char* y) /*简化算法*/ { char * str3 = (char *)malloc(80) char *z = str3; /*指针z指向数组str3*/ while (*z++ = *x++); z--; /*去掉串尾结束标志*/ while (*z++ = *y++); z = str3; /*将str3地址赋给指针变量z*/ return(z); } |
char *str_cnct(char *x, char* y) /*简化算法*/ { If(x == NULL) { Return NULL; } char * str3 = (char *)malloc(80) char *z = str3; /*指针z指向数组str3*/ while (*z++ = *x++); z--; /*去掉串尾结束标志*/ while (*z++ = *y++); z = str3; /*将str3地址赋给指针变量z*/ note: return(z);
} Main() { Char *p = str_cnct("abcd", "ddeee"); If(p != NULL) { Free(p); p = NULL }//yezhizhen } |
int getKeyByValude(char *keyvaluebuf, char *keybuf, char *valuebuf, int * valuebuflen) { int result = 0; char *getbuf = new char[100]; memset(getbuf, 0, sizeof(getbuf));
char *trimbuf = new char[100]; memset(trimbuf, 0, sizeof(trimbuf));
int destlen = strlen(keyvaluebuf);
if (keybuf == NULL || keyvaluebuf == NULL || valuebuf == NULL/* || valuebuflen == NULL*/) { result = -1; return result; }
if (strstr(keyvaluebuf, keybuf) == NULL)// strstr函数返回一个指针,它指向字符串str2 首次出现于字符串str1中的位置,如果没有找到,返回NULL。 { result = -1; return result; } else { for (int i = 0; i < destlen; i++) { if (*keyvaluebuf == '=') { *keyvaluebuf++; break; } keyvaluebuf++; } while (*keyvaluebuf != '\0') { *valuebuf = *keyvaluebuf; valuebuf++; keyvaluebuf++; } *valuebuf = '\0'; }
int len = strlen(valuebuf); return result; } |
//char *p = "abcd11111abcd2222abcdqqqqq"; //字符串中"abcd"出现的次数。 //要求你自己写一个函数接口,并且写出测试用例。 //完成功能为:求出"abcd"字串出现的次数 //输入: int getSubCount(char *str, char *substr, int * mycount) { int ret = 0; char *p = str; char *sub = substr; int count = 0;
if (str==NULL || substr==NULL || mycount == NULL) { ret = -1; return ret; }
//char *p = "abcd11111abcd2222abcdqqqqqabcd"; //char *p2 = NULL; //p2 = p; do { p = strstr(p, sub); if (p!= NULL) { count++; //++后缀操作符优先级高,所以先执行*p操作 然后地址++ *mycount++; p = p + strlen(sub); } else { break; } } while (*p != '\0'); //printf("count:%d \n", count);
//mycount是实参的地址 *(实参的地址) *mycount = count; return ret; } |
05重复的错误何时休
#include "stdio.h" #include "stdlib.h" #include "string.h"
void copy_str21_modify(char *from, char *to) { int i = 0; if (*from != '\0')//要先考虑空串 { printf("ddddd"); } for (; *from != '\0'; from++, to++) { *to = *from; } *to = '\0'; printf("to:%s", to); printf("from:%s", from); }
void copy_str_err(char *from, char *to) { for (; *from != '\0'; from++, to++)//要先考虑空串 { *to = *from; } *to = '\0'; printf("to:%s", to); printf("from:%s", from); }
//字符串逆序 int mainaaaa() { char buf1[100] = "abcdefg"; char to[100]; copy_str_err(buf1, to); }
//越界场景 int main00000000000() { char from[5] = "abcde"; printf("\n %s", from); getchar(); return 0; } |
3.7const专题
- const基础知识(用法、含义、好处、扩展)
int main() { const int a; int const b; //上面两者一样
const char *c; char * const d; //这样限定指针的话就要为它赋初值,不然没有任何意义 char buf[100] const char * const e;
return 0; }
Int func1(const) 初级理解:const是定义常量 const意味着只读 |
含义: //第一个第二个意思一样 代表一个常整形数 //第三个 c是一个指向常整形数的指针(所指向的内存数据不能被修改,但是本身可以修改) //第四个 d 常指针(指针变量不能被修改,但是它所指向内存空间可以被修改) //第五个 e一个指向常整形的常指针(指针和它所指向的内存空间,均不能被修改) |
Const好处 //合理的利用const, //1指针做函数参数,可以有效的提高代码可读性,减少bug; //2清楚的分清参数的输入和输出特性(参数列表中被const限定了的是传入参数) |
结论: //指针变量和它所指向的内存空间变量,是两个不同的概念。。。。。。 //看const 是放在*的左边还是右边 看const是修饰指针变量,还是修饰所指向的内存空变量 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?