在c语言中谈论字符串
一、存储:c语言中没有字符串类型,所以用char *类型的指针变量指向或者用字符指针存放字符串;
二、
'\0':字符串
默认以'\0'结尾,若是不写,编译器会默认加上;
所以存放字符串的
数组大小应该是strlen+1;(eg:char arr[ ] = "abcd";此时数组的大小默认是4+1;);
三、
内存位置:当字符串是保存在指针变量时,在内存中字符串是被放在
字符常量区的,是
不可被修改的,而此时的
指针变量仅仅保存的是字符串的首元素字符的地址,若此时该指针变量是在代码块内部简单定义的,在内存中该指针变量是被保存在栈中的;
当字符串被保存在数组中时,字符串是充当数组元素被保存在数组中的,若此时数组是在代码块内部简单定义的,则此时在内存中,字符串就被保存在栈上,可以被修改;
四
、函数使用:c语言中提供的字符串函数
1、strlen函数
size_t strlen( const char * string );
返回字符串长度(该字符串长度是无符号数):不包括'\0';
eg:该代码返回的结果为1。
char *str1 = "abcd";
char *str2 = "abc";
if(strlen(str2) - strlen(str1) > 0){
return 1;
}
else{
return 0;
}
原因:strlen函数返回值为无符号数,所以无符号数减去无符号数永远是无符号数,所以此处的条件判断永远为真。
2、strcpy函数
char *strcpy( char *
strDestination
, const char *
strSource
);
将源字符串整体拷贝给目标字符串,返回目标字符串:保证要将
源字符串的'\0'也复制给目标字符串。
3、
strncpy函数
char *strncpy( char *
strDest
, const char *
strSource
, size_t
count
);
将源字符串的count个字符拷贝给目标字符串,返回目标字符串:当源字符串的长度
与count相等,不会默认加'\0'。
4
、strcat函数
char *strcat( char *
strDestination
, const char *
strSource
);
将源字符串整体(包括'\0')拼接在目标字符串从'\0'开始的位置:不能自己给自己拼接,原因是:源字符串的'\0'已经被覆盖,不能结束。
5
、strncat函数
char *strncat( char *
strDest
, const char *
strSource
, size_t
count
);
将源字符串的count个字符拼接在目标字符串从'\0'开始的位置:拼接完成后会默认加上'\0'。
6
、strstr函数
char *strstr( const char *
string
, const char *
strCharSet
);
寻找子串函数,返回一个指针,指向strCharSet在字符串中的第一次出现的位置。
7
、strcmp函数
int strcmp( const char *
string1,
const char *
string2
);
比较两个字符串,返回1(string1>string2)、0(string1 == string2)、-1(string1 <string2)。
8
、strncmp函数
int strncmp( const char *
string1
, const char *
string2
, size_t
count
);
比较两个字符串中count个字符,返回值同上。
9
、strchr函数
char *strchr( const char *
string
, int
c
);
在字符串中找字符,返回一个指针,指向字符串中第一次出现的c。
10、strrchr函数
char *strrchr( const char *
string
, int
c
);
从字符串右边开始找字符c,返回一个指针,
指向字符串中最后一次出现的c。
11、strpbrk函数
char *strpbrk( const char *
string
, const char *
strCharSet
);
在字符串查找指定字符集中的字符,返回string中第一个出现在strCharSet中的字符的地址。
12、strpan函数
size_t strspn( const char *
string
, const char *
strCharSet
);
查找第一个子字符串,返回string中开始部分匹配strCharSet中字符的个数。
13、strcspn函数
size_t strcspn( const char *
string
, const char *
strCharSet
);
在字符串中查找子字符串,返回string中开始部分出现的不在strCharSet中的字符个数。
14、strtok函数
char *strtok( char *
strToken
, const char *
strDelimit
);
第一个参数:操作字符串;第二个参数:定义了用作分隔符的字符集合;
功能:根据strDelimit分割字符串
原理:找到下一个分隔符,并将其替换为'\0',结束此次分割;
当第一个参数不为空时,函数将找到第一个分隔符,strtok函数将保存它在字符串中的位置;
当第一个参数不为空时,函数将在同一个字符串中被保存的位置开始,查找下一个分隔
char str[] = " hello, my_word."
char *del = " ,_.";
char *split = strtok(str, del);
while(split != NULL){
printf("%s\n",spilt);
spilt = strtok(NULL, del);
}
输出结果为:
hello
my
word
15、strerror函数
char *strerror( int
errnum
);
返回错误码所对应的错误信息:erron,错误码(0:成功;非0:失败),全局变量。
内存操作函数
此类函数均是以字节操作。
1
、memcpy函数:字节拷贝函数
void *memcpy( void *dest, const void *src, size_t count );
2
、memmov函数:字节拷贝函数
void *memmove( void *dest, const void *src, size_t count );
两个函数的区别见谈论c的memcpy与memmove函数
3、memset函数:按字节整体赋值函数
void *memset( void *dest, int c, size_t count );
第一个参数:目标内存地址;
第二个参数:赋值;
第三个参数:要赋值的内存大小(字节单位)。
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<Windows.h>
//模拟实现strlen的三种方式
//方式1:计数器方式
int my_strlen1(const char *str)
{
int count = 0;
while (*str){
count++;
str++;
}
return count;
}
//strlen的返回值为count:(是无符号数!!!)
//方式2:递归(不创建临时变量)
int my_strlen2(const char *str)
{
if (!*str){
return 0;
}
return 1 + my_strlen2(str + 1);
}
//方式3:指针-指针
int my_strlen3(const char *str)
{
char *p = str;
while (*p){
p++;
}
return p - str;//尾-头
}
//模拟实现strcpy
char *my_strcpy(char *des, const char *src)
{
assert(des);
assert(src);//判断是否为空
char *ret = des;
while (*des = *src){//保证src的'\0'也被复制
des++;
src++;
}
return ret;//返回拷贝后的des
}
//模拟实现strncpy
//特点:当src_len == num时, 复制完成后不加'\0'
char *my_strncpy(char *des, const char *src, int num)
{
assert(des);
assert(src);
char *ret = des;
while (num--){
*des = *src;
des++;
src++;
}
return ret;
}
//模拟实现strcat
//不可以自己拼接自己:从目标字符串的'\0'开始覆盖,所以结果是不会退出,因为源字符串已无'\0'
char *my_strcat(char *des, const char *src)
{
assert(des);
assert(src);
char *ret = des;
while (*des){//从des的'\0'开始复制
des++;
}
while (*des = *src){
des++;
src++;
}
return ret;//返回拼接完成后的des
}
//模拟实现strncat
//特点:拼接完默认加'\0'
char *my_strncat(char *des, const char *src, int num)
{
assert(des);
assert(src);
char *ret = des;
while (*des){//从des的'\0'开始复制
des++;
}
while ((num--) && (*des = *src)){
des++;
src++;
}
return ret;
}
//模拟实现strstr(子串查找)
char *my_strstr(const char *des, const char *src)
{
assert(des);
assert(src);
char *d = (char *)des;
char *ds = NULL;
char *s = (char *)src;
while (*d){//如果在此字符串des已经判断到了'\0',则退出,未找到子串
ds = d;
s = src;
while (*s && *ds && *ds == *s){
ds++;
s++;
}
if (!*s){//如果在此*s == 0,则子串已找到
return d;
}
if (!*ds){//如果在此*ds == 0,则des已经找完,未找到子串
return NULL;
}
//走到这说明while循环是因为*ds!=*s跳出的
d++;
}
}
//模拟实现strcmp
int *my_strcmp(const char *src, const char *des)
{
assert(des);
assert(src);
int ret = 0;
while (!(ret = *(unsigned char *)src - *(unsigned char *)des) && *des){//将较大几率不成立的条件放置前面判断
//此处判断条件,没有判断*src为空:(原因)当判断条件1成立时说明src和des相等,此时会去判断条件2
//当条件2成立,则退出,此时代表ret == 0(也可以说明此时src == 0;(src-des == 0))
src++;
des++;
}
if (ret < 0){
ret = -1;
}
else if (ret > 0){
ret = 1;
}
else{
ret = 0;
}
return ret;
}
//模拟实现strncmp
int *my_strncmp(const char *src, const char *des, int num)
{
assert(des);
assert(src);
int ret = 0;
while ((num--) && !(ret = *(unsigned char *)src - *(unsigned char *)des) && *des){
src++;
des++;
}
if (ret < 0){
ret = -1;
}
else if (ret > 0){
ret = 1;
}
else{
ret = 0;
}
return ret;
}
//模拟实现strchr
//查找字符串s中首次出现字符c的位置
char *my_strchr(const char *str, char ch)
{
assert(str);
char *tmp = str;
while (*tmp != '\0' && *tmp != ch){
tmp++;
}
if (*tmp == ch){
return tmp;
}
else{
return NULL;
}
}
//模拟实现memcpy:以字节位基本操作单位
//赋值数字节长度的内存;以空指针类型来接收
void *my_memcpy(void *des, const void *src, int size)
{
//字节为单位:强转一个字节为单位的类型
assert(des);
assert(src);
char *des_ch = (char *)des;
unsigned char * src_ch = (unsigned char *)src;
while (size){
*des_ch = *src_ch;
des_ch++, src_ch++;
size--;
}
return des;
}
//模拟实现memmove
void *my_memmove(void *des, const void *src, int size)
{
assert(des);
assert(src);
char *des_ch = (char *)des;
unsigned char * src_ch = (unsigned char *)src;
if (des_ch <= src_ch || des_ch >= src_ch + size){//类型完整才能进行指针运算
//从前往后拷贝的情况
while (size--){
*des_ch = *src_ch;
des_ch++, src_ch++;
}
}
else{
//从后向前拷贝的情况
des_ch = des_ch + size - 1;
src_ch = src_ch + size - 1;
while (size--){
*des_ch = *src_ch;
des_ch++, src_ch++;
}
}
return des;
}
int main()
{
/*char *str = "anxsdfj12";
printf("%d\n", my_strlen1(str));
printf("%d\n", my_strlen2(str));
printf("%d\n", my_strlen3(str));*/
/*char *src = "qweasdz765";
char des[20];
printf("%s\n", my_strcpy(des, src));*/
/*char *src = "abcd efgh 123";
char des[15] = "zxcv asdf 456";
printf("%s\n", my_strncpy(des, src, 13));*/
/*char *src = "hjklg123";
char des[20] = "asdf";
printf("%s\n", my_strcat(des, src));*/
/*char *src = "hjklg123";
char des[12] = "asdf";
printf("%s\n", my_strncat(des, src, 8));*/
/*char *src = "asdf";
char *des = "qwasuitasdfcxnz";
printf("%s\n", my_strstr(des, src));*/
/*char *src = "abcdefg";
char *des = "abcdekg";
printf("%d\n", my_strcmp(src, des));*/
char *src = "abcdewg";
char *des = "abcdekg";
printf("%d\n", my_strncmp(src, des, 6));
/*char *str = "safjqla";
char ch = 'q';
printf("%s\n", my_strchr(str, ch));*/
//char src[10] = "qweasdz";
//int size = strlen(src) + 1;
//char des[20];
printf("%s\n", my_memcpy(des, src, size));//打印结果:qweasdz
printf("%s\n", my_memcpy(src, src + 1, size));//打印结果:weasdz
printf("%s\n", my_memcpy(src + 1, src, size));//打印结果:qqqqqqqq
printf("%s\n", my_memmove(des, src, size));//打印结果:qweasdz
printf("%s\n", my_memmove(src, src + 1, size));//打印结果:weasdz
printf("%s\n", my_memmove(src + 1, src, size));//打印结果:weasdz
memcpy(des, src, size);
printf("%s\n", src);//打印结果:qweasdz
memcpy(src, src + 1, size);
printf("%s\n", src);//打印结果:weasdz
//memcpy(src + 1, src, size);//第5种情况
//printf("%s\n", src);//结果为:qqweasdz
//printf("%s\n", memmove(src + 1, src, size));//打印结果:qweasdz//说明:返回拷贝的值
//memmove(des, src, size);
//printf("%s\n", src);//打印结果:qweasdz
//memmove(src, src + 1, size);
//printf("%s\n", src);//打印结果:weasdz
memmove(src + 1, src, size);//第5种情况
printf("%s\n", src);//结果为:qqweasdz
system("pause");
return 0;
}