字符数组
char word[] = { 'H','e','l','l','o','!'};
字符数组不是C语言的字符串,因为不能用字符串的方式做计算
字符串
char word[] = { 'H','e','l','l','o','!','\0' };
int i;
int len = sizeof(word) / sizeof(char);
//len 为数组的长度
for (i = 0; i < len; i++){
printf("word[%d]=%c\n", i, word[i]);
}
//通过数组的方式可以遍历字符串
运行结果如下:
word[0]=H
word[1]=e
word[2]=l
word[3]=l
word[4]=o
word[5]=!
word[6]=
C语言的字符串是以字符数组的形态存在的,不同于字符数组,它是以0(整数0)结尾的一串字符
- 0或’\0’是一样的,但是和’0’不同。
- 0是标志字符串的结束,但它不属于字符串的一部分
- 计算字符串长度的时候不包含这个0
- 字符串以数组的形式存在,以数组或指针(更多情况下)的形式访问
- 相邻的字符串常量会被自动连接起来
- 不能通过运算符对字符串做运算 (与python相比较)
- 唯一特殊的地方就是字符串字面量可以用来初始化字符数组
以及string.h标准库提供了一系列处理字符串的函数
字符串变量
以下都是字符数组变量,但是具有不同的表现形式
char *str = "hello";
此时我有一个名叫str的指针,它指向了一个字符数组 hello
至于这个hello在哪里呢,先不告诉你
char word[] = "hello";
有一个字符数组,里面放着hello
char line[10] = "hello";
字符数组有10个字节,往里面放了一个hello (5个字符占6个字节)
这个数组的长度是6,结尾还有表示结束的0
字符串常量
char* s1 = "hello";
//s1是一个指针,初始化为指向一个字符串常量
//s[0] = 'B'; error
等同于 const char *s;
//只能读 不能改
char* s2 = "hello";
int i; //i为本地变量
printf("s1=%p\n", s1);
printf("s2=%p\n", s2);
printf("&i=%p\n", &i);
运行结果
s1=004A7B30
s2=004A7B30 //指向相同字符串字符量的指针被赋予相同的值
&i=00EFF990 //s所指向得字符串离这个i的值离得很远
//被放在代码段不可修改 在很远的地方 只读
如果要对字符串进行修改,应该用数组构造字符串
char s3[] = "hello";
//数组形式可以修改字符串 在本地变量里
编译器会把放在不可读的 hello 拷贝一份
printf(("s3=%p\n", s3);
s3[1] = 'B' //可以改变
运行结果
s1=009C7B30
s2=009C7B30
&i=00CFF870
s3=00CFF860
//s3也是一个很大的值 在本地变量中
指针还是数组?
数组形式: 这个字符串在这里
- 作为本地变量空间自动被回收
指针形式: 这个字符串不知道在哪里
- 处理参数
- 动态分配空间
如果要构造一个字符串—>数组
如果要处理一个字符串—>指针
char *是字符串吗?
- 字符串可以表示为 char* 的形式
- char* 不一定是字符串
- 本意是指向字符的指针,也可能是指向的是 字符的数组
- 只有当它所指的字符数组有结尾的0时,才能说它所指的是字符串
字符串赋值
char *t = "title";
char *s;
s=t
- 这个代码并没有产生新的字符串
t所指的字符串,对s任何操作就是对t做的
字符串输入输出
char string[8];
scanf("%s", string);
printf("%s", string); //%s读单词
scanf 读入一个单词(到tab/blankspace/enter为止)
不知道读入的内容的长度,scanf是不安全的
安全输入
char string[8];
scanf("%7s",string);
//这个数字应该比数组长度小1
下一次读接着读直到()停
野指针
char *string; //不直接是字符串类型,它只是定义的一个指针,指向某一个字符串
scanf("%s",string);
//没有对string初始化为0,所以不一定每一次运行都出错
空字符串
char buffer[100] = '''';
这是一个空的字符串 buffer[0] == '\0' 有效
char buffer[] = '''';
希望编译器去决定字符串的长度
这个数组的长度只有1
字符串数组
char **a;
a是一个指针,指向另一个指针,那个指针指向一个字符串
char a[][]
第二维有要确切的值
char a[][10] = {
"hello",
"world",
"helloworld " //数组界限溢出
};
程序参数
//一个整数 一个字符串 整数告诉我们字符串有多大
int main(int argc, char const *argv[])
//argv[0]是命令本身
{
int i;
for ( i=0; i<argc; i++ ){
printf("%d:%s\n", i, argv[i]);
}
return 0;
}
单字符的输入输出
int putchar(int c)
向标准输出写一个字符
返回写了几个字符
返回错误: EOF(-1)表示写失败
end of file 文件结束
int getchar(void)
从标准输入读入一个字符
返回类型是int是为了返回EOF(-1)
int main(int argc, char const* argv[])
//argv[0]是命令本身
{
int ch;
while ((ch = getchar()) != EOF) {
putchar(ch);
}
printf("over")
return 0;
}
CTRL+Z
退出循环 CTRL+C
退出程序
string.h
#include<stdio.h>
#include<string.h>
strlen
length
size_t strlen(const char *s)
const保证strlen不会改变s
char line[] = "hello";
printf("strlen=%d\n", strlen(line));
printf("sizeof=%d\n", sizeof(line));
return 0;
strlen=5
sizeof=6 //多一个'\0'
自己定义strlen函数
int mylen(const char* s) {
int idx = 0;
while (s[idx]!='\0') {
idx++;
}
return idx;
}
strcmp
compare
int strcom(const char*s1, const char *s2)
返回值:
0 : s1==s2
1 : s1 > s2
-1:s1 < s2
char s1[] = "abc";
char s2[] = "abc";
printf("%d\n", s1 == s2);
//== 比较的是两个字符串的地址是否一样
//地址当然不同,所以结果都是false
printf("%d\n", strcmp(s1, s2));
0
0
自行定义strcmp函数
- 数组
int mystrcmp(const char* s1, const char* s2) {
int idx = 0;
int ret = 0;
while (s1[idx]==s2[idx]&&s1[idx]!='\0') {
idx++;
}
if (s1[idx] - s2[idx] == 0) {
ret = 0;
}
else if (s1[idx] - s2[idx] < 0) {
ret = -1;
}
else {
ret = 1;
}
return ret;
}
- 指针
int mystrcmp(const char* s1, const char* s2) {
int idx = 0;
int ret = 0;
while (*s1 == *s2 && *s1!= '\0') {
s1++;
s2++;
}
if (*s1 - *s2 == 0) {
ret = 0;
}
else if (*s1 - *s2 < 0) {
ret = -1;
}
else {
ret = 1;
}
return ret;
}
strcpy
copy
char*t strcpy(char *restrict dst,const char *restrict src)
把src的字符串拷贝到dst
src
:srouce
dst
:destination
- restrict表明src和dst不重叠
- 返回dst
- 为了能链起代码来
char* dst = (char*)malloc(strlen(src) + 1);
strcpy(dst,src);
- 数组
char* mycpy(char* dst, const char* src) {
int idx = 0;
while (src[idx]) {
dst[idx] = scr[idx];
idx++;
}
dst[idx] = '\0';
return dst;
- 指针
char* mycpy(char* dst, const char* src) {
char *ret = dst;
while (*src) {
*dst++ = *src++;
}
*dst = '\0';
return ret;
}
char* mycpy(char* dst, const char* src) {
char *ret = dst;
while (*dst++ = *src**)
;
/*空的循环*/
*dst = '\0';
return ret;
}
strcat
catenate 连接
char * stract(char*restrict s1, const char *restrict s2);
- 把s2拷贝到s1的后面,接成一个长的字符串
- 返回s1
- s1必须拥有足够的空间
与copy相类似
- strcpy dst[0]
- strcat dst[strlen(dst)]
安全问题
- dst没有足够的空间
安全版本
- char*t strncpy(char *restrict dst,const char *restrict src, size_t n);
- charstract(charrestrict s1, const char *restrict s2, size_t n);
- int strncmp(const char*s1, const char *s2, size_t n);
//比较前几个字符是不是相同,就没有必要考虑后面的字符,故可以用n来限制长度
字符串搜索函数
字符串中找字符
char * strchr (const char *s, int c);
//从左边找过来
char * strrchr (const char *s, int c);
//从右边找过来
返回NULL表示没有找到
int main() {
char s[] = "hello";
char* p = strchr(s, 'l');
printf("%s\n", p);
p = strchr(p + 1, 'l');
printf("%s\n", p);
return 0;
}
int main() {
char s[] = "hello";
char* p = strchr(s, 'l');
char c = *p;
*p = '\0';
char* t = (char*)malloc(strlen(p) + 1);
strcpy(t, s);
printf("%s\n", t);
free(t);
return 0;
}
字符串中找字符串
char * strstr (const char s1, const chars2);
char * strcasestr (const char s1, const chars2);
//忽略字母大小写