目录
int data[ ] = {1,2,3,4,5};和整型数组一个道理,char str[ ] = {'h','e','l','l','0'};
因为本函数可以无限读取,易发生溢出。如果溢出,多出来的字符将被写入到堆栈中,这就覆盖了堆栈原先的内容,破坏一个或多个不相关变量的值
char *strcpy(char* dest, const char *src);strcpy(p,"zhonglibo122233");//字符串拷贝函数
gets用法只能够在Linux下使用无法再Windows下使用
第九个assert字符串函数来断言跟if-else一样的道理
第1个、初识字符-第一个字符数组
常见字符,字符数组的 定义的几种方式和输出方式
- 定义的几种格式
- 和整型一样
int data[ ] = {1,2,3,4,5};和整型数组一个道理,char str[ ] = {'h','e','l','l','0'};是字符串变量
- 改进char str[ ] = "hello";是字符串常量,不予许被修改
- 一般用char *p =“hello”
- 第3和第4的区别:3是字符串变量可以被修改,4是字符串常量,不予许被修改。
#include <stdio.h>
int main()
{
int data[] = {1,2,3,4,5};//整形数组初始化
char c = 'c';//一个字符写法
char cdata [] = {'h','e','l','l','o'};//字符数组定义
char cdata2[] = "World";//最常用的方式
char *pchar = "Project";//指针方式定义
char *p;//野指针,并没有明确的内存指向,危险
*p = 'a';
cdata2[3] = 'm';
printf("%s",cdata2);//最好用的输出
putchar('\n');
puts(cdata2);
//*pchar = 'm';
puts("end");
/*for(int i = 0;i<5;i++){
printf("%d ",data[i]);
}
putchar('\n');
for(int i = 0;i<5;i++){
printf("%c ",cdata[i]);
}
putchar('\n');
for(int i = 0;i<5;i++){
printf("%c ",cdata2[i]);
}
putchar('\n');
for(int i = 0;i<5;i++){
printf("%c ",*(pchar+i));//指针方式输出
}*/
return 0;
}
第2个、和整型数组在存储上的区别
- 和整型数组在存储上的区别
3、多了结束标志‘\0’
#include <stdio.h>
#include <string.h>
//strcpy strcmp strcat strstr
int main()
{ //字符串和字符数组的区别;
int data[] = {1,2,3,4,5};//整形数组初始化
//请计算数组data的元素个数
char cdata [] = {'h','e','l','l','o'};//字符数组定义,字符串的结束标志'\0'
char cdata2[] = "hello";//最常用的方式
int len = sizeof(data)/sizeof(data[0]);//int 整形
printf("len = %d\n",len);
len = sizeof(cdata2)/sizeof(cdata2[0]);//char 型
printf("len = %d\n",len);
len = sizeof(cdata)/sizeof(cdata[0]);
printf("len = %d\n",len);
printf("%s\n",cdata);
return 0;
}
第3个、sizeof和strlen的区别
C语言中的
sizeof
和strlen
是两个常用的函数,用于获取变量的大小和字符串的长度。它们有以下区别:
sizeof
是一个运算符,用于获取变量或数据类型的字节大小。它返回值的类型是size_t
。sizeof
可以用于任何数据类型,包括基本数据类型(如int
、float
等)和自定义数据类型(如结构体、数组等)。对于数组,sizeof
返回整个数组的字节大小;而对于指针,sizeof
返回指针本身的字节大小,而不是指针指向的对象的大小。strlen
是一个库函数,用于获取字符串的长度,即不包括字符串末尾的空字符\0
的字符个数。它返回值的类型是size_t
。strlen
只能用于字符串数组(字符数组)或字符指针(指向字符串的指针)。- 需要注意的是,
strlen
函数要求字符串必须以空字符结尾,否则可能导致不可预测的结果或内存访问错误。
int arr[5];
size_t size1 = sizeof(arr); // 返回整个数组的字节大小
size_t size2 = sizeof(int); // 返回int类型的字节大小
char str1[] = "Hello";
char *str2 = "World";
size_t len1 = strlen(str1); // 返回字符串"Hello"的长度
size_t len2 = strlen(str2); // 返回字符串"World"的长度
#include <stdio.h>
#include <string.h>
void test()
{
}
//strcpy strcmp strcat strstr
int main()
{
char cdata[128] = "hello";//'\0';
void (*ptest) ();
ptest = test;
printf("sizeof: = %lu\n",sizeof(cdata));//关键字sizeof是计算整个类型大小
printf("strlen: = %lu\n",strlen(cdata));//strlen是计算字符串长度一定要记得区分使用
//计算有效字节的大小
char *p = "hello"; //常量
//p是一个char *,sizeof来计算的时候,得出是计算多少个字节来表示一个地址
printf("sizeof:p = %lu\n",sizeof(p));
printf("sizeof:char * = %lu\n",sizeof(char *));
printf("sizeof:int * = %lu\n",sizeof(int *));
printf("sizeof: test = %lu\n",sizeof(test));
printf("sizeof: ptest = %lu\n",sizeof(ptest));
printf("sizeof:char = %lu\n",sizeof(char));
printf("strlen: = %lu\n",strlen(p));
return 0;
}
第4个malloc动态开辟内存空间
- malloc,函数原型 void *malloc(size_t size),C 库函数 void *malloc(size_t size) 分配所需的内存空间,并返回一个指向它的指针。realloc
- realloc,函数原型 void *realloc(void *ptr, size_t size)扩容,C 库函数 void *realloc(void *ptr, size_t size) 尝试重新调整之前调用 malloc 或 calloc 所分配的 ptr 所指向的内存块的大小。
- free
C 库函数 void free(void *ptr) 释放之前调用 calloc、malloc 或 realloc 所分配的内存空间。释放,防止内存泄露,防止悬挂指针,野指针的一种
- memset(p,'0',12);用于清理字符串空间,函数原型 void *memset(void *str, int c, size_t n)
- 输出字符串
puts()
printf("%s",p);
- 获取字符串
scanf("%s",p)
gets
char * gets ( char * str );
因为本函数可以无限读取,易发生溢出。如果溢出,多出来的字符将被写入到堆栈中,这就覆盖了堆栈原先的内容,破坏一个或多个不相关变量的值
- 计算长度strlen
- 拷贝
strcpy
char *strcpy(char* dest, const char *src);strcpy(p,"zhonglibo122233");//字符串拷贝函数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//char *strcpy(char* dest, const char *src);//函数原型
int main()
{
char *p;//野指针
p = (char *) malloc(1);//p有了自己的内存空间和具体的指向
*p = 'c';//指向一个字符串,这种操作不可取
free(p);//free释放空间
p = NULL;//不用就让他NULL防止悬挂,释放,防止内存泄露,也是野指针的一种
p = (char *)malloc(12);//开辟字符串空间
if(p == NULL){
printf("malloc error\n");
exit(-1);//用于单片机开发很吃内存空间的判断
}
memset(p,'0',12);//用于清理字符串空间
printf("扩容地址:%x\n",p);//扩容前地址
int len = strlen("zhonglibo1029");//计算长度
int newLen = len - 12 + 1;//长度 - 12 + 1,加一是斜杆0;
realloc(p,newLen);//扩容地址
printf("扩容地址后:%x\n",p);
strcpy(p,"zhonglibo122233");//字符串拷贝函数
puts(p);//输出自己的字符串
puts("end");//打印查看是否会执行,会不会段错误
//printf("%c\n",*p);
return 0;
}
第五个gets、strcpy、strncpy、
gets用法只能够在Linux下使用无法再Windows下使用
#include <stdio.h>
int main()
{ char *p = "zhonglibo handsome";//定义指针一个字符串
char str[128] = {'\0'};//定义一个字符数组初始化为0
puts(p);//puts输出
printf("%s\n",p);//printf()输出字符串
puts("请输入一个字符串");
//scanf("%s",str);
gets(str);
puts(str);
return 0;
}
1、5-funcsl.c:12:2: warning:函数' gets '的隐式声明[-Wimp .c]
licit-function-declaration)得到(str);
2、5-funcsl.c:(.text+0x74):警告:' gets'函数是危险的
不会被使用。
strcpy 、strncpy
#include <stdio.h>
#include <string.h>
int main()
{
char s1[32] = "helloworld";
char s2[32] = {0};
strcpy(s2,s1);//把s1拷贝到s2,把后面拷贝到前面,//把s1拷贝到s2中
printf("%s\n",s2);//输出s2
char s3[32] = "helloworld";
char s4[32] = "11111111112222222222";
strcpy(s4,s3);//会拷贝\0导致覆盖无法拷贝后面数字
printf("%s\n",s4);
char s5[32] = "11111111112222222222";//重新定义一个数字字符
strncpy(s5,s3,10);//s5重新拷贝并指定10个
//printf("%s\n",s5);
//s5[10] = '\0'; // 手动添加终止符
printf("%s\n",s5);
return 0;
}
第6个strncat-字符串拼接
#include <stdio.h>
#include <string.h>
int main()
{
char s1[32] = "hello";
char s2[32] = "world";
strcat(s1,s2);//strcat函数拼接
//strncat(s1,s2,2);
printf("%s\n",s1);//把s2字符串接到s1,
strncat(s1,s2,2);//指定字符串拼接
printf("%s\n",s1);//把s2字符串接到s1,
return 0;
}
字符段拼接详解-自己实现字符串拷贝函数
这个程序演示了三种不同的字符串拼接方法。
1. `myStrcat` 函数使用了两个指针来进行字符串拼接。首先使用 `assert` 函数确保传入的目标字符串和源字符串不为空。然后,指针 `des` 指向目标字符串的末尾,通过移动指针找到末尾位置。然后,在一个循环中,将源字符串 `src` 的字符逐个复制到目标字符串 `des` 所指的位置,直到遇到空字符为止。最后,在源字符串的末尾添加一个空字符,并返回目标字符串的起始指针。
2. `myStrcat2` 函数使用了库函数 `strcpy` 和 `strlen` 来进行字符串拼接。首先通过 `strlen` 函数找到目标字符串 `des` 的末尾位置,然后使用 `strcpy` 函数将源字符串 `src` 的内容复制到目标字符串 `des` 的末尾。最后返回目标字符串的起始指针。
3. `myStrcat3` 函数与 `myStrcat` 的实现方式类似,不同之处在于使用了不同的循环结构。首先使用一个循环找到目标字符串 `des` 的末尾位置,然后通过另一个循环将源字符串 `src` 的内容逐个复制到目标字符串的末尾。最后,在源字符串的末尾添加一个空字符,并返回目标字符串的起始指针。
在 `main` 函数中,我们声明了一个字符数组 `str` 用于存储目标字符串,同时声明了一个字符指针 `p` 并指向字符串 " handsome"。然后,通过调用 `myStrcat3` 函数,将字符串 `p` 拼接到 `str` 之后。最后,使用 `puts` 函数将拼接后的字符串输出到屏幕上。
注释部分可以根据需要取消注释以测试其他的拼接方法。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// 第一个字符串复制函数,基本版
char* myStrcpy(char *des, char *src) {
if (des == NULL || src == NULL) {
return NULL; // 若源或目标字符串指针为空,则返回NULL
}
char *bak = des; // 保存目标字符串的起始地址
while (*src != '\0') { // 循环直到源字符串末尾
*des = *src; // 复制字符从源到目标
des++; // 目标地址递增
src++; // 源地址递增
}
*des = '\0'; // 在目标字符串的末尾添加终止字符'\0'
return bak; // 返回目标字符串的起始地址
}
// 第二个字符串复制函数,优化版
char* myStrcpy2(char *des, char *src) {
if (des == NULL || src == NULL) {
return NULL; // 若源或目标字符串指针为空,则返回NULL
}
char *bak = des; // 保存目标字符串的起始地址
while (*src != '\0') { // 循环直到源字符串末尾
*des++ = *src++; // 复制字符从源到目标,并同时递增指针
}
*des = '\0'; // 在目标字符串的末尾添加终止字符'\0'
return bak; // 返回目标字符串的起始地址
}
// 第三个字符串复制函数,修正后的正确版本
char* myStrcpy3(char *des, char *src) {
if (des == NULL || src == NULL) {
return NULL; // 若源或目标字符串指针为空,则返回NULL
}
char *bak = des; // 保存目标字符串的起始地址
while ((*des++ = *src++)); // 复制字符直到'\0',赋值表达式的结果为复制的字符,循环直到字符为'\0'
return bak; // 返回目标字符串的起始地址
}
char* myStrncpy(char *des, char *src, int count) {
if (des == NULL || src == NULL) {
return NULL; // 若源或目标字符串指针为空,则返回NULL
}
char *bak = des; // 保存目标字符串的起始地址
while (*src != '\0' && count > 0) { // 复制字符直到源字符串末尾或已复制指定数量的字符
*des++ = *src++;
count--; // 每复制一个字符,计数器减1
}
if (count > 0) {
while (count > 0) { // 如果目标数组还有空间,则填充'\0'
*des++ = '\0';
count--;
}
return des;
}
*des = '\0'; // 添加终止字符'\0'
return bak; // 返回目标字符串的起始地址
}
int main() {
char str[128] = {'\0'}; // 初始化一个足够大的字符数组来存储复制的字符串
char *p = "zhonglibo handsome"; // 源字符串
myStrncpy(str, p, 6); // 使用myStrncpy复制前6个字符
puts(str); // 输出复制的字符串
return 0; // 程序正常结束
}
第7个strncat-字符串函数来比较字符串的大小关系
这段代码主要是演示了字符数组之间的比较操作。代码中使用了
strcmp()
函数来比较字符串的大小关系。首先,声明了三个字符数组变量
char s1[32]
、char s2[32]
、char s3[32]
,分别存储了字符串"helloworld"、“helloboy"和"helloboy”。接下来,通过
strcmp()
函数进行字符串比较。strcmp()
函数会根据ASCII码对s1和s2进行比较,返回一个整数值。如果该值大于0,则表示s1大于s2;如果该值等于0,则表示s1等于s2。在代码中,通过
strcmp(s1, s2)
进行比较,由于"s1"的ASCII码大于"s2"的ASCII码,所以输出了"helloworld > helloboy"。然后,通过
strcmp(s2, s3)
进行比较,由于"s2"和"s3"的内容完全相同,所以输出了"helloboy = helloboy"。最后,程序返回0,表示正常结束执行。
#include <stdio.h>
#include <string.h>
int main()
{
char s1[32] = "helloworld";
char s2[32] = "helloboy";
if(strcmp(s1,s2) > 0)
{
printf("%s > %s\n",s1,s2);
}
char s3[32] = "helloboy";
if(strcmp(s2,s3) == 0){
printf("%s = %s\n",s2,s3);
}
return 0;
}
第8个strchr-strrchr字符串函数来查找对应字符
这段代码演示了如何使用`strchr()`和`strrchr()`函数在字符串中查找特定字符的位置。
首先,声明了两个字符数组变量`char s1[32]`和`char s2[32]`,分别存储了字符串"helloworld"和"helloboy"。
接下来,通过`strchr(s1, 'w')`函数查找字符串中第一次出现字符'w'的位置,并使用`printf()`函数打印出结果。`strchr()`函数返回一个指向字符'w'的指针,如果找不到该字符,则返回NULL。所以在这段代码中,输出的结果是"welloworld",因为找到了字符'w',指针指向该位置。
然后,通过`strchr(s1, 'l')`函数查找字符串中第一次出现字符'l'的位置,并使用`printf()`函数打印出结果。`strchr()`函数返回一个指向字符'l'的指针。在这段代码中,输出的结果是"lelloworld",因为找到了第一个字符'l',指针指向该位置。
最后,通过`strrchr(s1, 'l')`函数查找字符串中最后一次出现字符'l'的位置,并使用`printf()`函数打印出结果。`strrchr()`函数返回一个指向字符'l'的指针。在这段代码中,输出的结果是"ld",因为找到了最后一个字符'l',指针指向该位置。
最后,程序返回0,表示正常结束执行。
#include <stdio.h>
#include <string.h>
int main()
{
char s1[32] = "helloworld";
char s2[32] = "helloboy";
printf("%s\n", strchr(s1,'w'));
printf("%s\n", strchr(s1,'l'));
printf("%s\n", strrchr(s1,'l'));
return 0;
}
第9个assert字符串函数来断言跟if-else一样的道理
这段代码演示了字符串拷贝函数`myStrcpy()`和`myStrncpy()`的实现,并进行了一些测试。
首先,代码使用了`assert()`断言来确保传入的目标字符串和源字符串不为NULL。这是一种运行时的检查机制,如果条件为假(即0),则会打印错误信息并终止程序运行。
接下来,定义了三个字符串拷贝函数`myStrcpy()`、`myStrcpy2()`和`myStrcpy3()`,它们的功能都是将源字符串拷贝到目标字符串中,并返回目标字符串的起始地址。
接下来,定义了字符串拷贝函数`myStrncpy()`,它还额外接受一个整数`count`参数,表示最多拷贝的字符个数。如果源字符串的长度大于`count`,则只拷贝前`count`个字符,如果源字符串的长度小于`count`,则在目标字符串末尾补充`\0`直到拷贝了`count`个字符。
在`main()`函数中进行了一些测试。首先定义了一个字符数组`str[128]`,并初始化为空字符。然后使用赋值语句`b=a`来判断`a`是否等于字符`'m'`,如果相等,则输出"ok"。接下来,定义了一个指向常量字符串的指针`p`,并调用`myStrcpy()`函数将常量字符串拷贝到字符数组`str`中。最后,使用`puts()`函数打印出拷贝后的字符串。
最后,程序返回0,表示正常结束执行。
#include <stdio.h>
#include <string.h>
#include <assert.h>
char* myStrcpy(char *des, char *src)
{
//assert 的作用是现计算表达式 expression ,如果其值为假(即为0),
//那么它先向 stderr 打印一条出错信息,然后通过调用 abort 来终止程序运行
assert(des != NULL && src != NULL);//断言,
char *bak = des;
while( *src != '\0'){
*des = *src;
des++;
src++;
}
*des = '\0';
return bak;
}
char* myStrcpy2(char *des, char *src)
{
if(des == NULL || src == NULL){
return NULL;
}
char *bak = des;
while( *src != '\0'){
*des++ = *src++;
}
*des = '\0';
return bak;
}
char* myStrcpy3(char *des, char *src)
{
if(des == NULL || src == NULL){
return NULL;
}
char *bak = des;
while( (*des++ = *src++) != '\0');
*des = '\0';
return bak;
}
char* myStrncpy(char *des, char *src, int count)
{
if(des == NULL || src == NULL){
return NULL;
}
char *bak = des;
while( *src != '\0' && count>0){
*des++ = *src++;
count--;
}
if(count > 0){
while(count > 0){
count--;
*des++ = '\0';
}
return des;
}
*des = '\0';
return bak;
}
int main()
{
char str[128] = {'\0'};
//char *pstr = NULL;
char a = 'm';
char b;
if((b=a) == 'm'){
printf("ok\n");
}
char *p = "zhonglibo handsome";
myStrcpy(str, p);
puts(str);
return 0;
}
9.1断言失败
言(assert)在程序开发过程中通常用来检查程序的假设条件是否成立。当断言失败时,它会打印一条出错信息,并终止程序的执行。
在这段代码中,断言的作用是检查传入的目标字符串指针
des
和源字符串指针src
是否为NULL
,即是否为空指针。如果有任意一个指针为NULL
,那么断言失败,会导致程序终止执行。在
main()
函数中,定义了一个字符数组str[128]
并初始化为空字符。然后定义了一个字符指针pstr
并将其初始化为NULL
。接下来定义了一个字符变量a
并赋值为字符'm'
,然后定义了另一个字符变量b
。通过(b=a) == 'm'
的判断条件,判断a
是否等于字符'm'
,如果相等,则输出"ok"。然后,定义了一个指向常量字符串的指针
p
,该字符串是"zhonglibo handsome"。接下来调用myStrcpy()
函数,但在调用过程中,传递给该函数的目标字符串指针pstr
为NULL
,这将导致断言失败。当断言失败时,通常会打印一条出错信息到 stderr(标准错误输出),然后终止程序的执行。在这段代码中,由于断言失败,所以不会输出"ok",而是会在控制台打印出错误信息。
#include <stdio.h>
#include <assert.h>
char* myStrcpy(char *des, char *src)
{
//assert 的作用是现计算表达式 expression ,如果其值为假(即为0),
//那么它先向 stderr 打印一条出错信息,然后通过调用 abort 来终止程序运行
assert(des != NULL && src != NULL);//断言,
char *bak = des;
while( *src != '\0'){
*des = *src;
des++;
src++;
}
*des = '\0';
return bak;
}
char* myStrcpy2(char *des, char *src)
{
if(des == NULL || src == NULL){
return NULL;
}
char *bak = des;
while( *src != '\0'){
*des++ = *src++;
}
*des = '\0';
return bak;
}
char* myStrcpy3(char *des, char *src)
{
if(des == NULL || src == NULL){
return NULL;
}
char *bak = des;
while( (*des++ = *src++) != '\0');
*des = '\0';
return bak;
}
char* myStrncpy(char *des, char *src, int count)
{
if(des == NULL || src == NULL){
return NULL;
}
char *bak = des;
while( *src != '\0' && count>0){
*des++ = *src++;
count--;
}
if(count > 0){
while(count > 0){
count--;
*des++ = '\0';
}
return des;
}
*des = '\0';
return bak;
}
int main()
{
char str[128] = {'\0'};
char *pstr = NULL;
char a = 'm';
char b;
if((b=a) == 'm'){
printf("ok\n");
}
char *p = "zhonglibo handsome";
myStrcpy(pstr, p);
puts(str);
return 0;
}
第10个字符串比较strcmp使用和实现
- 这些是头文件的引用,包括了
stdio.h
(标准输入输出)、string.h
(字符串操作)、assert.h
(断言)。- 这部分定义了自定义的字符串比较函数
myStrcmp
。函数接受两个字符指针参数str1
和str2
,用于比较两个字符串的大小关系。代码中的实现逻辑如下:- 定义变量
ret
并初始化为 0,用于存储比较结果。- 定义变量
n_str1
和n_str2
并初始化为 0,用于存储累加字符串中各个字符的 ASCII 值。- 保存传入的指针参数
str1
和str2
到临时指针bakStr1
和bakStr2
。- 在一个循环中逐个比较两个字符串中对应位置的字符是否相等,直到遇到其中一个字符串的末尾或者遇到不相等的字符为止。
- 如果其中一个字符串没有遍历完,则重新从头遍历两个字符串,累加各个字符的 ASCII 值到
n_str1
和n_str2
。- 计算
n_str1
和n_str2
的差值并赋值给ret
。- 如果
ret
小于 0,则将ret
设置为 -1,表示第一个字符串小于第二个字符串。- 如果
ret
大于 0,则将ret
设置为 1,表示第一个字符串大于第二个字符串。在
main
函数中:- 定义了两个字符指针
p1
和p2
,分别指向两个字符串 “zhonmnlibod” 和 “zhonglizbod”。- 调用自定义的字符串比较函数
myStrcmp
,将两个字符串作为参数传入,比较它们的大小https://www.cnblogs.com/elesos/archive/2012/11/08/2759790.html
#include <stdio.h>
#include <string.h>
#include <assert.h>
int myStrcmp(char *str1, char *str2)
{
int ret = 0;
int n_str1 = 0;
int n_str2 = 0;
char *bakStr1 = str1;
char *bakStr2 = str2;
while( *str1 && *str2 && (*str1 == *str2)){
str1++;
str2++;
}
if(*str1 || *str2){
str1 = bakStr1;
str2 = bakStr2;
while(*str1){
n_str1 += *str1;
str1++;
}
while(*str2){
n_str2 += *str2;
str2++;
}
}
ret = n_str1 - n_str2;
if(ret < 0){
ret = -1;
}
if(ret > 0){
ret = 1;
}
return ret;
}
int main()
{
char *p1 = "zhonmnlibod";
char *p2 = "zhonglizbod";
int ret = myStrcmp(p1,p2);
if(ret == 0){
puts("两个字符串一样");
}
printf("RET = %d\n",ret);
return 0;
}