字符串
思路分析在注释
文章目录
提示:以下是本篇文章正文内容,下面案例可供参考
一、字符串的定义
- 字符串是由字符数组表示的,并且以空字符 ‘\0’ 结尾。
- 字符串的结尾由空字符 ‘\0’ 标识,这个字符用来表示字符串的终止。因此,字符串的实际长度比可见字符的数量多一个。
在C语言中,字符串可以用字符数组或字符指针来定义
// 字符数组---字符串变量
char str[ ] = {'h','e','l','l','0'};
char str1[] = "Hello"; // 实际上是 {'H', 'e', 'l', 'l', 'o', '\0'}
// 字符指针---字符串常量
char *str2 = "Hello, World!";
内存分配:使用字符指针定义的字符串是只读的,如果需要修改字符串的内容,应该使用字符数组。
数组越界:操作字符串时要注意数组越界的问题,确保数组有足够的空间来存储字符串及其终止符 '\0'.
1. 使用sizeof()计算他们的长度
#include <stdio.h>
int main()
{
char str[] = {'h','e','l','l','o'};
char str1[] = "hello";
int len = sizeof(str)/sizeof(str[0]);
printf("str的长度%d\n",len);
len = sizeof(str1)/sizeof(str1[0]);
printf("str1的长度%d\n",len);
return 0;
}
运行结果
使用字符数组初始化(char str[] = {'h', 'e', 'l', 'l', 'o'})时,数组的长度仅包括实际字符的数量,不包括空字符。
使用字符串字面量初始化(char str1[] = "hello")时,数组的长度包括字符串结束符 \0。
二、sizeof和strlen的区别
sizeof 和 strlen 是在C语言中用来处理数组和字符串的两个常用函数(或运算符),它们的功能和用途有显著区别
1.sizeof 操作符
- sizeof 是一个编译时运算符,用于计算变量、数据类型或表达式的大小(以字节为单位)。它可以用来计算任何数据类型的大小,包括基本类型(如int, char, float 等),结构体,数组等
2.strlen 函数
- strlen 是一个在 <string.h> 头文件中定义的库函数,用于计算以空字符(\0)结尾的字符串的长度(不包括空字符)。它只能用于 char 类型的字符串数组或字符串指针
代码如下(示例):
#include <stdio.h>
#include <string.h>
void test()
{
}
int main()
{
char str[] = "hello";// '\0'
void (*ptest)();
ptest = test;
printf("sizeof(str) :%d\n", sizeof(str)); // 6
printf("strlen(str) :%d\n", strlen(str)); // 5
char *p = "hello";
//p是一个char*类型,指向一个字符串,字符串以'\0'结束 sizeof来计算的时候,是计算指针的大小,而不是字符串的大小
printf("sizeof(p) :%d\n", sizeof(p)); // 8
printf("sizeof(char*) :%d\n", sizeof(char *)); // 8
printf("strlen(char) :%d\n", sizeof(char)); // 1
printf("strlen(int*) :%d\n", sizeof(int*)); // 8
printf("strlen(ptest) :%d\n", sizeof(ptest)); // 8
printf("strlen(p) :%d\n", strlen(p)); // 5
return 0;
}
三、动态开辟字符串
1.malloc函数
malloc 是 C 标准库中的一个函数,用于动态分配内存(在堆区)。它声明在 <stdlib.h> 头文件中。malloc 的全称是 “memory allocation”,其原型为
void *malloc(size_t size);
参数:
- size_t size:这是一个无符号整数类型,用于指定要分配的内存大小,以字节为单位。
返回值:
- malloc 返回一个 void * 类型的指针,指向已分配内存块的起始地址。
- 如果内存分配成功,返回值是一个非 NULL 的指针。
- 如果内存分配失败(例如系统没有足够的内存),返回值是 NULL。
注意:
使用 malloc 分配的内存需要手动释放(使用 free 函数),否则可能会导致内存泄漏。
始终检查 malloc 的返回值,以确保内存分配成功
2.realloc函数
realloc函数用于调整之前通过malloc或calloc分配的内存块的大小。它可以扩大或缩小内存块,并且可以保留原始内存块中的数据(如果内存被扩大,新的内存块可能会位于不同的位置)。如果新大小比原大小大,扩展部分的内容是未定义的,其原型为
void *realloc(void *ptr, size_t size);
参数
- ptr:指向要调整大小的内存块的指针。如果ptr为NULL,realloc的行为就像malloc一样
- size:新的内存块大小(以字节为单位)
返回值
- 返回一个指向新内存块的指针。如果失败,返回NULL,并且原内存块保持不变
3. free函数
free函数用于释放之前通过malloc、calloc或realloc分配的内存块。它将内存返回给系统,使得这些内存可以被重新分配。释放内存是防止内存泄漏的重要步骤,因为如果程序持续分配内存而不释放,将会耗尽可用内存,最终导致程序或系统崩溃。
void free(void *ptr);
参数
- ptr:指向要释放的内存块的指针。如果ptr为NULL,free什么也不做
4. memset函数
memset函数用于将指定的值设置为指定内存块的每个字节。这通常用于初始化内存,例如将数组中的所有元素设置为0或某个特定的值
void *memset(void *ptr, int value, size_t num);
参数
- ptr:指向要填充的内存块的指针。
- value:要设置的值,以整数形式传递,但会被转换为无符号字符。
- num:要设置的字节数。
返回值
- memset返回指向内存块的指针
使用示例
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *p; //野指针
p = (char*)malloc(2);//分配内存,p有了具体的内存指向
*p = 'a';
*(p + 1) = '\0'; // 添加空终止符 puts(p)期望一个以空字符('\0')结尾的字符串,puts会继续读取超出你分配的内存,这会导致未定义行为,可能打印出一些垃圾值。
puts(p);
free(p);//执行后p又是野指针
p = (char*)malloc(12);
memset(p,'\0',12);
printf("扩容地址:%x\n",p);
int len = strlen("hello world12324242");
int new_len = len - 12 + 1;
realloc(p,new_len);
printf("扩容后的地址:%x\n",p);
strcpy(p,"hello world12324242");
printf("%s\n",p);
free(p);
return 0;
}
四、几种字符串常用的API
1. strncpy函数
strncpy函数用于将字符串从源复制到目标,但最多复制n个字符。如果源字符串长度小于n,目标字符串的剩余部分将用空字符填充。
参数
- dest:指向目标字符串的指针
- src:指向源字符串的指针
- n:要复制的最大字符数。
返回值 - 返回目标字符串的指针(dest)
strncpy的行为
- 如果src的长度小于n,dest的剩余部分将用空字符填充。
- 如果src的长度大于或等于n,strncpy不会在dest的末尾添加空字符。
代码示例
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "hi";
char dest[10];
strncpy(dest, src, 10); // 复制源字符串到目标,最多10个字符
printf("dest: %s\n", dest); // 输出: dest: hi(后面跟随一些空字符)
return 0;
}
自己编写strncpy函数,实现相似功能
#include <stdio.h>
char* my_strncpy(char *dest,char *src, int count)
{
char *p = dest;
while(*src != '\0' && count>0)
{
*dest++ = *src++;
count--;
}
if (count>0)
{
while(count--)
{
*dest++ = '\0';
}
return p;
}
*dest = '\0';
return p;
}
int main() {
char a[50]="\0";
char *p = "nihao";
char *pchar = my_strncpy(a, p, 10);
puts(pchar);
puts(a);
return 0;
}
2. assert函数
assert函数用于在程序运行时进行断言检查,即在调试阶段检查程序中的某些假设是否成立。如果断言失败,程序将输出一条错误信息并终止运行。它是帮助开发人员在调试阶段发现和修复错误的有力工具。
//函数原型
void assert(int expression);
参数
- expression:一个整数表达式。当表达式为假(即值为0)时,assert会触发一个断言失败的错误。
3. strcat函数
strcat 是 C 标准库中的一个函数,用于将一个字符串追加到另一个字符串的末尾。它声明在 <string.h> 头文件中。strcat的原型为
char *strcat(char *dest, const char *src);
参数:
- char *dest:指向目标字符串的指针,该字符串必须有足够的空间容纳源字符串和原目标字符串的内容。
- const char *src:指向源字符串的指针,该字符串的内容将被追加到目标字符串的末尾。
返回值:
- 返回值是指向目标字符串 dest 的指针
代码示例
自己编写strcat函数,实现相似功能(使用两种方式)
char* my_strcat(char *dest,char *src)
{
assert(dest != NULL && src != NULL);
char *p = dest;
while(*dest != '\0')
{
*dest++;
}
while((*dest++ = *src++) != '\0')
*dest = '\0';
return p;
}
char* my_strcat1(char *dest,char *src)
{
assert(dest != NULL && src != NULL);
char *p = dest;
strcpy(dest+strlen(dest),src);
return p;
}
int main() {
char *pchar;
char a[50]="nihao";
char *p = "xiaoming";
//pchar = strcat(a,p);
pchar = my_strcat1(a,p);
puts(pchar);
puts(a);
return 0;
}
把src所指向的字符串(包括“\0”)复制到dest所指向的字符串后面(删除*dest原来末尾的“\0”)。要保证*dest足够长,以容纳被复制进来的*src。*src中原有的字符不变。返回指向dest的指针。