本期主要介绍字符串的使用以及常用的API!
目录
一、定义字符串的几种方式
//1.和整型数组一个道理 char str[]={'h','e','l','l','o'};
char str[]={'h','e','l','l','o'};
//2.改进. char str[]="hello";
char str[]="hello";
//3.一般用 char *p = "hello";
char *p = "hello";
#include <stdio.h>
int main()
{
//字符串的定义方式
//1.和整型数组一个道理 char str[]={'h','e','l','l','o'};
char str[]={'h','e','l','l','o'};
//2.改进. char str[]="hello"; 是字符串变量,可改变里面的值
char str1[]="hello";
//3.一般用 char *p = "hello"; 是字符串常量,不可改变里面的值
char *p = "hello";
printf("str1的字符串为%s",str1);
printf("p的字符串为%s",p);
return 0;
}
二、字符数组的存储方式
注:字符串会多了以'\0'结束为标志 char cdata[] = "hello";
#include <stdio.h>
int main()
{
int data[] = {1,2,3,4,5};
char cdata[] = "hello";
char cdata2[] = {'h','e','l','l','o'}; //字符串的结束标志
int lendata;
int lencdata;
int lencdata2;
//计算数组data的元素
lendata = sizeof(data)/sizeof(data[0]);
lencdata = sizeof(cdata)/sizeof(cdata[0]);
lencdata2 = sizeof(cdata2)/sizeof(cdata[0]);
printf("%d\n",lendata);
printf("%d\n",lencdata);
printf("%d\n",lencdata2);
return 0;
}
三、sizeof和strlen的区别
sizeof 是操作符, strlen 为函数;
sizeof 可以使用类型作为参数,如 int char; strlen 只能使用 char*做参数且以\0 为结尾
sizeof 为数组时候,不退化, 传递给 strlen 时数组会被退化成指针;
eg:
#include <stdio.h>
#include <string.h>int main()
{
char data[128] = "hello";
printf("sizeof的大小:%d\n",sizeof(data));
printf("strlen的大小:%d\n",strlen(data));
return 0;
}
2.sizeof一个char*时,得出是计算机用多少字节来表示一个地址。
eg:
#include <stdio.h>
#include <string.h>void test()
{
}
int main()
{
char data[128] = "hello";
//printf("sizeof的大小:%d\n",sizeof(data));
//printf("strlen的大小:%d\n",strlen(data));
char *pdata = "hello";
void (*ptest)();
ptest = test;
//pdata是一个char * sizeof来计算的时候,得出是计算机用多少字节来表示一个地址。
printf("sizeof pdata的大小: %d\n",sizeof(pdata));
printf("sizeof char *的大小:%d\n",sizeof(char *));
printf("sizeof int * 的大小:%d\n",sizeof(int *));
printf("sizeof char 的大小: %d\n",sizeof(char));
printf("sizeof test 的大小: %d\n",sizeof(test));
printf("sizeof ptest 的大小: %d\n",sizeof(ptest));
printf("strlen的大小:%d\n",strlen(data));
return 0;
}
四、动态开辟字符串
1.malloc
原型:void *malloc(size_t size),其中size_t size是指开辟多少个字节。
malloc函数的作用是动态分配内存,以解决静态内存定长、不能手动释放等缺陷。
char *p;
p = (char *)malloc(1);//防止野指针
*p = 'c';
2.free
原型: void free(void *ptr);
作用:1.释放,防止内存泄露 2.防止悬挂指针——野指针的一种
char *p;
p = (char *)malloc(1);//防止野指针
*p = 'c';
free(p);
p = NULL;
3.realloc(扩容)
原型: void *realloc(void *ptr,size_size); 其中size_siz表示在原基础上增加多少字节
尝试重新调整之前调用malloc或calloc 所分配的ptr所指向的内存块的大小。
char*p;
p = (char *)malloc(12);
p = "hasdhsiafpoasda12";
int len = strlen("hasdhsiafpoasda12");
int newlen = len-12+1;
realloc(p,newlen);
4.memset
原型: void *memset(void *str,int c,size_t n);
用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为‘ ’或‘/0’;
char*p;
p = (char *)malloc(12);
memset(p,'\0',12);//把开辟的内存空间全部初始化为\0
五、几种字符串常用的API
1.puts、printf、sprintf
原型:
#include <stdio.h>
int puts(const char *s);int printf ( const char * format, ... );
eg:
#include <stdio.h>
int main()
{
char *p = "hello";
puts(p);
printf("%s",p);
return 0;
}
1.2 sprintf
原型:
int sprintf( char *buffer, const char *format [, argument,...] );
除了前两个参数类型固定外,后面可以接任意多个参数。而它的精华,显然就在第二个参数:格式化字符串上。
2.scanf、fscanf、gets
scanf("%s",p);
gets();//char gets(char * str);
注:本函数可以无限读取,易发生溢出。如果溢出,多出来的字符将被写入到堆栈中,这就覆盖了堆栈原先的内容,破坏一个或多个不相关变量的值。
#include <stdio.h>
int main()
{
char *p = "hello";
char str[128] = {'\0'};
scanf("%s",p);
printf("请输入str:\n");
gets(str);
puts(str);
return 0;
}
#include <stdio.h>
原型:int fscanf(FILE*stream, constchar*format, [argument...]);
功能:为根据数据格式(format)从输入流(stream)中写入数据(argument);
参数:stream为文件指针,format为格式化字符串,argument 为格式化控制符对应的参数。
3. gets与getchar
区别:
1、gets函数是输入一行字符串,以回车结束,并且回车键会被过滤掉,不会被读回到字符串中。
2、而getchar()是读答取一个字符,包括回车键也会被读成一个字符。这个程序在输入name[i]前,用getchar()把之前scanf("%d",&num[i]);中,输入整数后按的回车键给读走,否则这个回车键会导致gets直接读到一个空字符串。
4. strcpy
原型:char * strcpy( char * dst, const char * src );
dst ->destination -指向用于存储复制内容的目标数组。
str ->source– 要复制的字符串。
strcpy是一种C语言的标准库函数,strcpy把从src地址开始且含有’\0’结束符的字符串复制到以dest开始的地址空间,返回值的类型为char*。
5. strncpy
原型:char *strncpy(char *dest, const char *src, size_t n)
把 src 所指向的字符串复制到 dest,最多复制 n 个字符。 当 src 的长度小于 n 时,dest 的剩余部分将用空字节填充。
eg:
#include <stdio.h>
#include <string.h>int main()
{
char des[128] = {'\0'};
char des1[128] = {'\0'};
char *stc = "hello";
char *p = "niaho";
strcpy(des,stc);
puts(des);
strncpy(des1,p,2);
puts(des1);
return 0;
}
5.1自己封装strcpy的原型
#include <stdio.h>
char* mystrcpy3(char *des,char *src)
{
if(des == NULL || src == NULL){
return NULL;
}
char *bak = des;
while(* src != '\0'){
*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++;
*src++;
}
*des = '\0';
return bak;
}char* mystrcpy(char *des,char *src)
{
if(des == NULL || src == NULL){
return NULL;
}
char *bak = des;
while( (*des++ = *src++) != '\0');
*des = '\0';
return bak;
}
int main()
{
char str[128] = {'\0'};
char *p = "hello";
mystrcpy3(str,p);
puts(str);
return 0;
}
比较高级的
while((*des++ = *src++) !='\0')`
类似于
char a = 'm';
char b;if((b=a)==m){
printf("ok~!");
}
5.2 自己封装strncpy的原型
#include <stdio.h>
char* mystrncpy3(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){
count--;
*des++ = '\0';
return des;
}
*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++;
*src++;
}
*des = '\0';
return bak;
}char* mystrcpy(char *des,char *src)
{
if(des == NULL || src == NULL){
return NULL;
}
char *bak = des;
while( (*des++ = *src++) != '\0');
*des = '\0';
return bak;
}
int main()
{
char str[128] = {'\0'};
char *p = "hello";
mystrncpy3(str,p,2);
puts(str);
return 0;
}
6.断言assert
它是个宏,并且作用并非"报错"。
assert() 的用法像是一种"契约式编程"
if(假设成立)
{
程序正常运行;
}
else
{
报错&&终止程序!(避免由程序运行引起更大的错误)
}
assert 宏的原型定义在 assert.h 中,其作用是如果它的条件返回错误,则终止程序执行。
assert 的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向 stderr 打印一条出错信息,然后通过调用 abort 来终止程序运行。
assert 的缺点是,频繁的调用会极大的影响程序的性能,增加额外的开销。
7. strcat 拼接
原型:char *strcat(char *des,const char *src);
char str[128] = "nihaoa";
char *p = "1245";
strcat(str,p);
puts(str);
7.1自己封装的strcat
#include <stdio.h>
#include <assert.h>
#include <string.h>char* mystrcat(char *des,char *src)
{
assert(des != NULL && src != NULL);
char *bak =des;
while(*des != '\0'){
*des++;
}
while((*des++ = *src++) != '\0');
*des = '\0';
return bak;
}char* mystrcat2(char *des,char *src)
{
assert(des != NULL && src != NULL);
char *bak =des;
strcpy(des+strlen(des),src);//des+strlen(des) 指把指针便宜strlen(des)这么长。
return bak;
}
int main()
{
char str[128] = "niha";
char *p = "hh";
mystrcat2(str,p);
puts(str);
return 0;
}
规则:把src所指向的字符串(包括‘\0’)复制到dest所指向的字符串后面(删除dest原来末尾的'‘\0'),要保证des足够长,以容纳被复制进来的src。src中原有的字符不变,返回指向des的指针。
7.2 c语言中 “=”和”==“的区别
1.“=” 是把“=”右边的值赋值给左边。
2.“==” 是将“==”左右的值作比较。
8. strcmp 比较
原型:int strcmp(const char* s1,const char *s2);
若s1=s2,则返回零;若s1<s2,则返回负数;若s1>s2,则返回正数;
if(!strcmp("ls","cmd")) return LS;
在if(表达式){语句} 条件语句里,如果表达式值为真的话,刚执行花括号里的语句;若表达式为假,刚不执行 对于if(!a)来说,要看你给a的初值是什么,如果是一个非零值的话,那么!a就是假,不执行语句; 如果a的初值为零,那么!a就是真,执行语句(另外,C++中把非零的数看作是真,零为假)
8.1自己封装的strcmp
#include <assert.h>
#include <stdio.h>
int MyStrCmp(const char* str1, const char* str2)
{
assert((str1 != NULL) && (str2 != NULL));//用于检查,如果为空就停止
while ((*str1 == *str2) && (*str1 != '\0') && (*str2 != '\0'))
{
str1++;
str2++;
}
return (*str1 - *str2);
}
int main(int args, char* argv[])
{
char s1[256]={0};
char s2[256]={0};int ret;
printf("please input s1:\n");
gets(a1);
printf("please input s2:\n");
gets(a2);
ret = MyStrCmp(s1,s2);if(ret ==0){
printf("s1 s2 is same\n");
}
}
9. strstr查找字符串
C语言中,strstr()函数用于找到子串在一个字符串中第一次出现的位置,在string.h头文件中。 例如:char *strstr(const char *str1, const char *str2) str1是总串,str2是需要匹配的第一个字串位置,返回值为char * 类型
9.1自己封装的strstr
#include <stdio.h>
#include <assert.h>
char *my_strstr(char const *pdest, char const *psrc)
{
const char *pstr1 = pdest;
const char *pstr2 = psrc;
const char *ptr = NULL;
assert(pdest);
assert(psrc);
if (*pstr2 == '\0')
{
return (char *)pstr1;
}
while (*pstr1 != '\0')
{
ptr = pstr1;
pstr2 = psrc;
while (*ptr != '\0' && *pstr2 != '\0'
&& *ptr == *pstr2)
{
ptr++;
pstr2++;
}
if (*pstr2 == '\0')
{
return (char *)pstr1;
}
pstr1++;
}
return NULL;
}
int main()
{
char *des = "abbbcdef";
char *str= "bcd";char *ret =NULL;
ret = my_strstr(des,str) ;printf("分割后:%s\n",ret);
return 0;
}
10.strtok分割字符
strtok的函数原型:
char* strtok (char* str, const char* sep)
1.包含在string.h头文件中
2.sep是个字符串,定义了用作分隔符的字符集合
3.第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记
4.strtok函数找到str中的下一个标记,并将其用’\0’结尾,返回一个指向这个标记的指针。(注意:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并可修改)
5.strtok函数的第一个参数不为NULL,函数将找到str中的第一个标记,strtok函数将保存它在字符串中的位置。
6.strtok函数的第一个参数为NULL,函数将在同一个字符串被保存的位置开始,查找下一个标记。
7.如果字符串中不存在更多的标记,则返回NULL指针。
11.chdir改变当前目录
chdir(const char * path);
函数说明:chdir()用来将当前的工作目录改变成以参数path 所指的目录
返回值执:行成功则返回0, 失败返回-1, errno 为错误代码.
12.access函数
int access(const char *pathname, int mode);
access函数用来判断指定的文件或目录是否存在(F_OK),已存在的文件或目录是否有可读(R_OK)、可写(W_OK)、可执行(X_OK)权限。F_OK、R_OK、W_OK、X_OK这四种方式通过access函数中的第二个参数mode指定。如果指定的方式有效,则此函数返回0,否则返回-1。
13. fflush函数
fflush函数 更新缓存区
函数定义:int fflush(FILE *stream); 函数说明:调用fflush()会将缓冲区中的内容写到stream所指的文件中去.若stream为NULL,则会将所有打开的文件进行数据更新
2、fflush(stdin):刷新缓冲区,将缓冲区内的数据清空并丢弃 fflush(stdout):刷新缓冲区,将缓冲区内的数据输出到设备