由于C语言中的字符串没有对应的字符串变量储存,所以在C语言中用字符数组存储字符串。字符数组的各个数组元素依次存放字符串的各个字符,字符数组的数组名代表该字符串的首地址。
字符数组的初始化
charc[8]={‘H’,‘e’,‘l’,‘l,‘o’};把6个字符分别赋值给c[0]到c[7]的8个元素,如果初值个数小于数组长度,则将这些字符赋给数组中前面那些元素,将其余元素自动赋值为空字符(’\0’)。字符个数大于数组长度则发生语法错误。
字符串与字符数组的区别
本质的区别在于“字符串结束标志的使用”,字符数组中的每个元素都可以存放任意的字符,并不要求最后一个字符是“\0”。但对于字符串来说必须以“\0”结束。
字符串的输入与输出
1.采用“%c”格式符,每次输入或者输出一个字符。
eg:用格式符“%c”逐个字符的输出一个字符数组。
#define _CRT_SECURE_NO_WARNINGS 1
#include"stdio.h"
int main()
{
char c[5] = { 'h', 'e', 'l', 'l', 'o' };
int i;
for (i = 0; i < (sizeof(c) / sizeof(c[0])); i++)
{
printf("%c", c[i]);
}
}
结果:
字符串处理函数
1.求字符串长度函数strlen()
调用新式:size_t strlen( const char *str)
功能:返回字符串str或者字符数组str中字符串的实际长度,不包括’\0’.
Eg:
#define _CRT_SECURE_NO_WARNINGS 1
#include"stdio.h"
int main()
{
char c[20]= "hello world";
printf("%d\n", strlen(c));
}
函数的模拟实现:(计数器模式)
#define _CRT_SECURE_NO_WARNINGS 1
#include"stdio.h"
int my_strlen(const char * str)
{
int count = 0;
while (*str)//遇到\0循环截止
{
count++;
str++;
}
return count;
}
main()
{
char *str = "addhcb";
char temp = my_strlen(str);
printf("%d\n", temp);
}
执行结果:
2.(不能创建临时变量的计数器)递归
int my_strlen(const char * str)
{
if (*str == '\0')
return 0;
else
return 1 + my_strlen(str + 1);//递归调用函数本身
}
main()
{
char *str = "addhcb";
char temp = my_strlen(str);
printf("%d\n", temp);
}
运行结果:
3.使用指针通过指针的的运算来计算字符个数:
int my_strlen(const char * str)
{
char*p = str;
while (*p != '\0')//指针p走到\0的位置处截止
{
p++;
}
return p - str;//从而计算字符串中的字符个数
}
main()
{
char *str = "addhcb";
char temp = my_strlen(str);
printf("%d\n", temp);
}
2.字符拷贝函数strcpy()
Copy a string.
函数调用形式:
char *strcpy( char *strDestination, const char *strSource );
功能:将原字符数组考到目标字符数组中去。
Eg:
int main()
{
char str1[20], str2[] = "dfsdsf";
strcpy(str1, str2);
printf("%s", str1);
}
模拟实现:通过循环把str中的字符赋给dest中。
char *my_strcpy(char *dest, const char*src)
{
assert(dest != NULL);//判断字符数组不为空
assert(src != NULL);
int len = strlen(src); int i;
for (i = 0; i < len+1; i++)//多拷贝一个\0
{
*dest = *src;
dest++;
src++;
}
}
int main()
{
char str1[20], str2[] = "dfsdsf";
my_strcpy(str1, str2);
printf("%s", str1);
}
执行结果
2.代码优化:
char *my_strcpy(char *dest, const char*src)
{
char *ret = dest;//定义ret来接收dest
assert(dest != NULL);//判断字符数组不为空
assert(src != NULL);
while ((*dest++ = *src++))//*的优先级大于后置++,当遇到\0循环截止
{
;
}
return ret;
}
运行结果:
memcpy()
调用形式:void *memcpy( void *dest, const void *src, size_t count );
1.函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
2.这个函数在遇到 ‘\0’ 的时候并不会停下来(strcpy()拷贝时遇到\0会停止。)。
3.如果source和destination有任何的重叠,他所复制的结果都是为定义的。
Eg:
在打印过程中拷贝了str1中的13个字符到str中,打印str结果为 i love you说明第11字符 \0也被拷贝到了str中。
模拟实现:
void * my_memcpy(void * dst, const void * src, size_t count)
{
void *ret = dst;
assert(dst);
assert(src);
while (count--)//控制循环次数
{
*(char*)dst = *(char*)src;
dst = (char*)dst+1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
char str[20], str1[] = { "i love you\0 baby" };
my_memcpy(str, str1, 13);
printf("%s\n", str);
}
运行结果:
strcat()
连接两个字符数组中的字符串,把str2连接到str1的后面,并自动覆盖str1所指字符串的尾部字符‘\0’,结果放在str1中,函数调用后得到str1的地址。
Eg:
void main()
{
char str1[30] = "hello";
char str2[] = "world";
strcat(str1, str2);
printf("%s", str1);
}
实现结果:
调用形式
char *strcat( char *strDestination, const char *strSource );
模拟实现:
char *my_strcat(char *dest, const char*src)
{
char *ret = dest;//接收dest的结果值
assert(dest != NULL);//保证字符数组不为空
assert(src != NULL);
while (*dest)//循坏截止条件:在遇到\0
{
dest++;//让dest地址走到\0位置处
}
while ((*dest++ = *src++))//把str中的得字符考到dest的后面。
{
;
}
return ret;
}
void main()
{
char str1[30] = "hello";
char str2[] = "world";
my_strcat(str1, str2);
printf("%s", str1);
}
运行结果:
strstr()
Find a substring.
判断字符串str2是否是str1的的字串,如果是返回str1字符串从str2第一次出现的位置开始到str1结尾的字符串。
调用形式:
char *strstr( const char *string, const char *strCharSet );
Eg:
void main()
{
char str1[20] = "sggdbnkscd";
char str2[] = "gdb";
char*p;
p=strstr(str1, str2);
puts(p);
}
运行结果:
模拟实现:
在
str2中的字符跟str1的数组进行比较一个位置进行比对直到str2中的最后一字符能在str1中与之对因就从str1中的开始位置输出剩余字符。否则从str1+1位置处在于str2进行比较。
char *my_strstr(const char* str1, const char* str2)
{
assert(str1);//确保不为空
assert(str2);
char *cp = (char*)str1;
char *substr = (char *)str2;
char *s1 = NULL;
if (*str2 == '\0')
return NULL;
while (*cp)
{
s1 = cp;
substr = str2;
while (*s1 && *substr && (*s1 == *substr))//确保两个数组没走到最后并且两个数组中的字符匹配。
{
s1++;
substr++;
}
if (*substr == '\0')
return cp;
cp++;
}
}
void main()
{
char str1[20] = "sggdbnkscd";
char str2[] = "gdb";
char*p;
p = my_strstr(str1, str2);
puts(p);
}
运行结果:
memmove()
用于拷贝字节,如果目标区域和源区域有重叠的话,memmove()能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,但复制后原内容将会被更改。但是目标区域没有重叠的话跟memcpy的作用是一样的。
调用形式:
void *memmove( void *dest, const void *src, size_t count );
Eg:
int main()
{
char str[] = "memmove can be very useful......";
memmove(str + 20, str + 15, 11);
puts(str);
return 0;
}
运行结果:
模拟实现:
void * my_memmove(void * dst, const void * src, size_t count)
{
void * ret = dst;
if (dst <= src || (char *)dst >= ((char *)src + count))
{
while (count--)
{
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
}
else {
dst = (char *)dst + count - 1;
src = (char *)src + count - 1;
while (count--)
{
*(char*)dst = *(char*)src;
dst = *(char*)dst - 1;
src = *(char*)src - 1;
}
}
}
int main()
{
char str[] = "memmove can be very useful......";
my_memmove(str + 20, str + 15, 11);
puts(str);
return 0;
}
运行结果: