目录
1.字符串的定义和使用
2.字符串的内存存放方式及结束标志
3.sizeof和strlen的区别
4.动态开辟字符串
4.1 malloc
4.2 free
4.3 realloc
4.4 memset
5.几种常用字符串的API
5.1输出字符串与获取字符串
5.2strcpy
5.3strncpy
6.assert函数
1.字符串的定义和使用
表示字符串的几种方式:
1.和整形数组表示一样
int main()
{
//int data[] = { 1,2,3,4,5 };
char cdata[] = { 'H','e','l','l','o' };
for (int i = 0;i < 5;i++)
{
printf("%c", cdata[i]);
}
return 0;
}
2.字符串变量(可以对某个字符进行操作)
int main()
{
char str[] = "hello";
for (int i = 0;i < 5;i++)
{
printf("%c", str[i]);
}
return 0;
}
3.字符串常量(只能用,不允许被操作)
int main()
{
char* pchar = "hello";
for (int i = 0;i < 5;i++)
{
printf("%c", *pchar++);
}
return 0;
}
//另一种写法
int main()
{
char* pchar = "hello";
printf("%s",pchar);
return 0;
}
4. putchar 和puts
int main()
{
putchar('a');
putchar('\n');
putchar('b');
return 0;
}
输出结果:
a
b
putchar( )只能输出一个字符, 换行也算作一个字符。
int main()
{
char* m = "abcd";
puts(m);
puts("hh");
return 0;
}
puts( )自带换行效果,可用输出字符串,且字符串可以用指针替代。
2.字符串的内存存放方式及结束标志
int main()
{
//字符串和字符数组的区别:
int data[] = { 1,2,3,4,5 };
char cdata[]={'h','e','l','l','o'};
char cdata2[] = "hello";
int len;
//计算数组data的元素个数,不同类型的数据记得用对应的方式
len = sizeof(data) / sizeof(data[0]);
printf("%d\n", len);
len = sizeof(cdata) / sizeof(char);//注意这里是char
printf("%d\n", len);
len = sizeof(cdata2) / sizeof(char);//注意这里是char
printf("%d\n", len);
return 0;
}
输出结果:
5
5
6
字符串类型, 默认多一个'\0',这是字符串的结束标志
3.sizeof和strlen的区别
int main()
{
char cdata[] = "hello";//带了一个\0
printf("sizeof: %d\n", sizeof(cdata));
printf("strlen: %d\n", strlen(cdata));
return 0;
}
输出结果为:
6
5
strlen能计算有效字符的长度
int main()
{
char cdata[128] = "hello";//带了一个\0
printf("sizeof: %d\n", sizeof(cdata));//siezeof计算的是整个空间长度
printf("strlen: %d\n", strlen(cdata));
return 0;
}
输出结果为:
sizeof:128
strlen: 5
记住:该用siezof( ) 和该用strlen( )的地方!
int main()
{
char* p = "hello";
printf("sizeof:p : %d\n", sizeof(p));
printf("sizeof:char* : %d\n", sizeof(char*));
printf("sizeof:int* : %d\n", sizeof(int*));//不管是什么类型的指针,就是用4个字节来表示
printf("sizeof:char : %d\n", sizeof(char));
printf("strlen : %d\n", strlen(p));
return 0;
}
计算结果为:
sizeof:p : 4
sizeof:char\* : 4
sizeof:int\* : 4
sizeof:char : 1
strlen : 5
因为p是一个 char* 的指针,而sizeof计算时,得出的是计算机用多少地址来表示一个地址
4.动态开辟字符串
4.1malloc
函数原型 void *malloc(size_t size),malloc可以按需开辟字符串空间。
C库函数 void *malloc(size_t size) 分配所需的内存空间,并返回一个指向它的指针。
int main()
{
char* p;//野指针,会报错
*p = 'c';
return 0;
}
用上malloc后,p有了具体的指向空间。同理,我们能开辟多个字符串空间
int main()
{
char* p;
p = (char*)malloc(1);//p有了具体的指向空间
*p = 'c';
printf("%c", *p);
return 0;
}
4.2 free
C 库函数 void free(void *ptr) 释放之前调用 calloc、malloc 或 realloc 所分配的内存空间。
作用1:释放,防止内存泄漏。 作用2:防止指针悬挂
int main()
{
char* p;
p = (char*)malloc(1);//p有了具体的指向空间
*p = 'c';
free(p);
p = (char*)malloc(12);
strcpy(p, "qmzhaha");
puts(p);
return 0;
}
对于上面的代码,由于p已经指向'c'占用了空间,后面又让p指向'qmzhaha',前面的p的空间就被挂起, 用free( )可以释放不使用的数据。(malloc在堆上开辟空间,普通的数组在栈上开辟空间)
4.3realloc
其次,"qmzhaha"小于12个字节,但当超出12时怎么办?我们需要用到realloc
函数原型 void *realloc(void *ptr, size_t size)能起到扩容作用
C 库函数 void *realloc(void *ptr, size_t size) 尝试重新调整之前调用 malloc 或 calloc 所分配的 ptr 所指向的内存块的大小。
int main()
{
char* p;
p = (char*)malloc(12);
int len = strlen("qmahahha2312213141421123");
int newlen=len-12+1;
realloc(p, newlen);
strcpy(p, "qmahahha2312213141421123");
puts(p);
return 0;
}
4.4 memset
p = (char*)malloc(12);
memset(p, '\0', 12);
能把malloc申请到的12个空间都初始化成'\0'
5.几种常用字符串的API
5.1输出字符串与获取字符串
puts(); printf("%s",p); scanf("%s",p);gets()
int main()
{
char* p = "i like running!";
char str[128] = { '\0' };
puts(p);
printf("%s\n", p);
strncpy(str, p, 6);//拷贝
puts(str);
puts("请输入字符串");
//scanf("%s",str);
gets(str);
puts(str);
return 0;
}
5.2strcpy
需要头文件**#include <string.h>**
5.2.1覆盖拷贝函数strcpy
函数原型:char* strcpy(char* destination, const char* resourse);
将source全覆盖拷贝到destination,返回值:char* 类型的 数组首地址
注意:
1.strcpy只用于字符串复制,遇到'\0'时停止,还会复制字符串的结束符'\0'; 所以源字符串必须以'\0'结束,也会将源字符串的'\0'拷贝到目标空间。
2.destination的空间必须>=source的空间。
5.2.2自己实现字符串拷贝函数
在学习strncpy前,自己先拟一个myStrcpy()函数来达到同样的效果,实现过程如下:
char* myStrcpy(char* des, char* src)
{
if (des == NULL || src == NULL)
{
return NULL;
}
char* bake ;//char一个备份地址去保存目标地址
bake = des ;
while (*src != '\0')
{
*des = *src;//拷贝
des++;//拷贝完最后一个字母后,地址都++,再次进入这个循环,则满足条件了
src++;
}
*des = '\0';
return bake;
}
int main()
{
char str[128] = { '\0' };
char* p = "i need a job!";
myStrcpy(str, p);//自己做一个函数,达到strncpy的效果
puts(str);
return 0;
}
关于while内其他两种写法
写法1
while (*src != '\0')
{
*des++=*src++;
}
写法2
while ((*des++=*src++)!= '\0')
5.3strncpy
5.3.1 覆盖拷贝函数strncpy
函数原型:char * strncpy(char *des, const char *src, size_t n);
拷贝字符串前n个字符到des,返回值为:des字符串起始地址
5.3.2自己实现strncpy
char* myStrncpy(char* des, char* src,int count)//赋值多少个字符
{
if (des == NULL || src == NULL)
{
return NULL;
}
char* bake = des;//char 一个备份地址去保存目标地址
while (*src != '\0'&& count>0)
{
*des++ = *src++;//拷贝
count--;
}
if (count > 0)
{
while (count > 0)
{
count--;
*des++ = '\0';
}
return des;
}
*des = '\0';
return bake;
}
int main()
{
char str[128] = { '\0' };
char* p = "i need a job!";
myStrncpy(str, p,6);//自己做一个函数,达到strncpy的效果
puts(str);
return 0;
}
6.assert函数
需要包含断言头文件#include<assert.h>,其相当于一个if语句。
if(假设成立)
{
程序正常运行;
}
else
{
报错&&终止程序!(避免由程序运行引起更大的错误)
}
assert作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向 stderr 打印一条出错信息,然后通过调用 abort 来终止程序运行。因此不能让(条件)为假
if (des == NULL || src == NULL)
{
return NULL;
}
将上方代码转化为assert为:
asssert(des != NULL && src != NULL)