在【C++】字符与字符数组 中已经介绍了C语言中形式的字符串,这里再进行深入介绍。
目录
字符串一般共有三种形式
1)字符数组
char buf[] = "hello";
2)char* 指针
char* str = "hello, world!"
这种有毒,我是vs2017,我使用2)这种方式就给我报错,必须使用3)这种方式。
3)字符串常量
const char* str = "hello, world!"
2)和3)都是字符指针,以上三种打印字符串的方式为
printf("%s", buf);
printf("%s", str);
字符串和数组最关键的得知道2个信息:首地址,长度
为什么C风格字符串不需要指定长度?
C风格字符串不需要另外制定长度,因为规定了结束字符。
字符串遍历
程序功能:遍历打印字符,其实就是打印字符串
#include "stdio.h"
int show_string(const char* str)
{
for (int i=0; ; i++)
{
char ch = str[i];
if (ch == 0)
{
break;
}
printf("%c", ch);
}
return 0;
}
int main()
{
const char* str = "Hello World!";
printf("%s", str);
char buf[] = "hello world!";
printf("%s\n", buf);
const char* str1 = "I am nick.";
show_string(str1);
return 0;
}
字符串长度如何计算
字符串长度:是指从头开始,一直到结束符,中间的字符的个数。(人为规定)
char str[16] = {'q','w','e',0,'r','t','y',}该字符串长度为3;
char str[128] = {0,'q','w','e',0,'r','t','y',}该字符串长度为0。
#include "stdio.h"
int get_length(const char* str)
{
int i = 0;
while (str[i])
i++;
return i;
}
int main()
{
const char* str1 = "I am nick.";
int str_length = get_length(str1);
printf("%d", str_length);
return 0;
}
/*
//run out
10
*/
字符串复制
复制字符串,是指将一个字符串的内容复制到目标字符串,包括结束符。(结束符之后的无效数据不被复制)
复制不是指针的改变,而是内存中出现了两份相同的字符串。
#include "stdio.h"
int main()
{
//第一种方式
char src[] = "hello";
char dst[128];
int i = 0;
while (src[i])
{
dst[i] = src[i];
i++;
}
dst[i] = 0;
printf("%s",dst);
//第二种方式
char src_1[] = "hello";
char dst_1[128];
int j = 0;
while (1)
{
dst_1[j] = src_1[j];
if (dst_1[j] == 0) break;
j++;
}
printf("%s", dst_1);
return 0;
}
字符串比较
比较方法:逐个字符依次比较,当所有字符全部相同时才认为两者相等。
#include "stdio.h"
int main()
{
char input[128];
scanf_s("%s", input, 10);
if (input == "yes")//这比较的是2个地址,永远也不会相等。所以要想比较这两个字符串,必须一个一个字符的比较。
{
printf("OK");
}
else
{
printf("Cancel");
}
return 0;
}
其结果永远为“Cancel”,永远也不会相等,你这比较的是2个地址。所以要想实现字符串比较,只能一个一个字符的比较。
默认规定:单个字符比较大小,小于返回-1,等于返回0,大于返回1。
#include "stdio.h"
int compare_char(char a, char b)
{
if (a < b)
return -1;
else if (a == b)
return 0;
else
return 1;
}
int main()
{
char input[128];
scanf_s("%s", input, 10);
char candidate[] = "yes";
int i = 0;
while (1)
{
int mark = compare_char(input[i], candidate[i]);
if (mark != 0)
{
printf("Cancel");
break;
}
if(input[i] == 0 && candidate[i] == 0)
{
printf("OK");
break;
}
i++;
}
return 0;
}
删除字符
从一个字符串中删除一个或多个字符。
从字符串中间删除一个字符,那么成本很高。比如字符串"hello",删除字符‘e’,那么就需要将'e'后面的字符都向前移动一个。
程序功能:删除一个字符。
#include "string.h"
void erase(char text[], int index)
{
int len = strlen(text);
for (int i = index; i < len; i++)
{
text[i] = text[i + 1];
}
}
int main()
{
char str[10] = "hello";
erase(str, 1);
return 0;
}
程序功能:字符串中删除'a'字符。(所有的'a'都需要删除)
#include "stdio.h"
#include "string.h"
void erase_argument(char text[], char del)
{
int size = strlen(text);
char* final_text = (char*)malloc(size+1); //需要加一个结束符0
int count = 0;
for (int i = 0; i < size; i++)
{
if (text[i] == del)
{
continue;
}
final_text[count] = text[i];
count++;
}
final_text[count] = 0;
strcpy(text, final_text);
free(final_text);
}
int main()
{
char str_1[] = "Hello, Nancy, would you like tom?";
erase_argument(str_1, 'o');
return 0;
}
插入字符
向一个字符串中间插入字符。
include "string.h"
void insert_char(char text[], int index, char ins)
{
int len = strlen(text);
for (int i=len; i>index; i--)
{
text[i] = text[i - 1];
}
text[index] = ins;
}
int main()
{
char str[10] = "hello";
insert_char(str, 2, 'P');
return 0;
}
字符串分割
头部:首地址
尾部:结束符
中间有若干个字符
程序功能:修改指定索引的字符。
int main()
{
char str_1[] = "Hello world!";
str_1[3] = 'P';
return 0;
}
小结:char str_1[]申明的字符串是可以修改的,char* str_1申明的字符串不能修改。具体可以参考博客
直接利用首地址
我们要了解到str_1是该字符串的首地址,所以str_1+1表示第二个字符的地址,所以可以使用如下方式能得到新的字符串:
char* str = str_1+1;
程序功能:将字符串"Hello world"分割为"Hello"和"world"2个字符串。
int main()
{
char str[] = "Hello world";
str[5] = 0;
char* part_0 = str;
char* part_1 = str + 6;
return 0;
}
小结:添加一个结束符,然后直接分割开就好。
程序功能:通用字符串分割,分割符号为','和'\0'和' '和'\t'
#include "string.h"
int split(char text[], char* parts[])
{
int count = 0; //分段的个数
int start = 0; //每一分段的首地址
int flag = 0; //遍历text,标识当前是否处于有效字符
int stop = 0; //是否到达结束
for (int i=0; !stop; i++)
{
char ch = text[i];
if (ch == 0)
{
stop = 1; //停止循环
}
if (ch == ',' || ch == '\0' || ch == ' ' || ch == '\t')
{
if (flag)
{
flag = 0;
text[i] = 0;
parts[count] = text + start;
count++;
}
}
else
{
if (!flag)
{
flag = 1;
start = i;
}
}
}
return count;
}
void my_split(char text[], char* parts[])
{
int count = 0;
int start = 0;
int flag = 0; //flag记录是否进入下一段字符串
int size = strlen(text);
for (int i=0; i <= size; i++) //这里一定是<=,不然结束符取不到就会有问题
{
char ch = text[i];
if (ch == ',' || ch == ' ' || ch == '\t' || ch == '\0') //这里'\0'是为了找到最后的结束符,不然程序最后一个字符串就不能正常结束。
{
if (flag) //这里特别容易漏。这步的作用是防止连续的 分隔符 截断合理的分割
{
text[i] = 0; //插入结束符
parts[count] = text + start; //找到起始位置
flag = 0;
count += 1;
}
}
else
{
if (!flag)
{
start = i;
flag = 1;
}
}
}
}
int main()
{
char test_str[] = "Hello, my name is nick";
char* parts[16];
split(test_str, parts);
char test_str_1[] = "Hello, my name is nick";
char* parts_1[16];
my_split(test_str_1, parts_1);
return 0;