10.1-1字符数组
- char word[] = {'H','e','l','l','o','!'};
这(指1)不是C语言的字符串,因为不能用字符串的方式做计算
- char word[] = {'H','e','l','l','o','!','\0'};
word[0] | H |
word[1] | e |
word[2] | l |
word[3] | l |
word[4] | o |
word[5] | ! |
word[6] | \0 |
字符串
- 以0(整数0)结尾的一串字符
- 0或者'\0'是一样的,但是和'0'不同
- 0标志字符串的结束,但它不是字符串的一部分
- 计算字符串长度的时候不包含这个0
- 字符串以数组的形式存在,以数组或者指针的形式访问
- 更多的是以指针的形式
string.h里有很多处理字符串的函数
- C语言的字符串是以字符数组的形态存在的
- 不能用运算符对字符串做运算
- 通过数组的方式可以遍历字符串
- 唯一特殊的地方是字符串字面量可以用来初始化字符数组
- 以及标准库提供了一系列字符串函数
10.1-2字符串变量
- char *str = "Hello";
- char word[] = "hello";
- char line[10] = "Hello";结尾编辑器会自动补0,多占据一个位置
- "Hello会被编译器变成一个字符数组放在某处,这个数组的长度是6,结尾还有表示结束的0"
- 两个相邻的字符串常量会被自动连接起来
字符串常量
char* s = "Hello,world";
- s是一个指针,初始化为指向一个字符串常量
- 由于这个常量所在的地方,所以实际上s是const char *s,但是由于历史的原因,编译器接受不带const的写法
- 但是试图对s所指的字符串做写入会导致严重的后果
- 如果有两处相同的地方,指针会同时指向同一处地方,所以指针必须是只读的
- 如果需要修改字符串,应该用数组:
- char s[] = "Hello,world!";
- 这个数组跟指针的区别就是,指针指向某一处地方,而数组则表示就在我这里
- 会将放在不可写的"Hello,world!"数组内容拷贝到你的s那里去
当我们需要一个字符串的时候,指针还是数组?
- char*str = "Hello";
- char word[] = "Hello";
- 数组:这个字符串在这里
- 作为本地变量空间自动被回收
- 指针:这个字符串不知道在哪里
- 处理参数
- 动态分配空间
- 用在只需要只读的,不打算去往里面写入东西的。表达函数的参数。
- 如果要构造一个字符串->数组
- 如果要处理一个字符串->指针
char*是字符串?
- 字符串可以表达为char*的形式
- char*不一定是字符串
- 本意是指向字符的指针,可能指向的是字符的数组(就像int*一样)
- 只有当char*所指向的字符数组有结尾的0,才能说它所指的是字符串
10.1-3字符串输入输出
- char*t = "title";
- char*s;
- s = t;
- 并没有产生新的字符串,只是让指针s指向了t所指的字符串,对s的任何操作就是对t做的
- char string[8];
- scanf("%s",string);
- printf("%s\n",string);
- scanf读入一个单词(到空格、tab或回车为止),但scanf这样是不安全的,因为不知道要读入内容的长度
安全的输入
- char string[8];
- scanf("%7s",string);
- 在%s中间可以加入数字来让编译器知道需要限制在多少字符范围内(或者说最多允许读入的字符数量),比如%7s,限制在7个字符范围(超出部分就不会读入了)
常见错误
- char*string;
- scanf("%s",string);
- 以为char("%s".string);
- 以为char*是字符串类型,定义了一个字符串类型的变量string就可以直接使用了
- 由于没有对string初始化为0,所以不一定每一次运行都出错(实际上这是错误的,指针用错了,没有指向一个确定的地方)
空字符串
- char buffer[100] = "";
- 这是一个空的字符串,buffer[0] == '\0'
- char buffer[] = "";
- 这个数组的长度只有1!所以后面放不下任何的字符串
10.1-4字符串数组以及程序参数
字符串数组
- char **a
- a是一个指针,指向另一个指针,那个指针指向一个字符(串)
- char a
- 一个错误的二维数组,因为没有说明几列,所以会报错
- 可以修改成char a[],本质上就相当于a[0]--->char
程序参数
- int main(int argc,char const*argv[])
- argv[0]是命令本身
- 当使用Unix的符号链接时,反应符号链接的名字
#include
intmain(intargc, charconst*argv[])
{
inti;
for( i=0; i<argc; i++){
printf("%d:%s\n",i,argv[i]);
}
return0;
}
10.2-1单字符输入输出,用putchar和getchar
putchar
- int putchar(int c);
- 向标准输出写一个符号
- 返回写了几个字符,EOF(-1)表示写失败
getchar
- int getchar(void);
- 从标准输入读入一个字符(跟scanf的区别是scanf可以一次性读入多个字符)
- 返回类型是int是为了返回EOF(-1)
- window-->Ctrl-Z
- Unix-->Ctrl-D(返回EOF)
- Ctrl-C会将shell与实际上显示的的通道关闭掉了
#include
intmain(intargc,charconst*argv[])
{
intch;
while( (ch=getchar()) !=EOF ){
putchar(ch);
}
printf("EOF\n");
return0;
}
在我们输入的东西(在键盘上敲出来的东西被称为行编辑的工作)的时候,那些都会被暂时放在shell里(类似缓冲区域),当我们按下回车之后,才会发送到实际上显示的地方上
10.2-(2-6)字符串函数strlen
string.h
- strlen
- size_t strlen(const char *s);
- 返回s的字符串长度(不包括结尾的0)
- strcmp
- int strcmp(const char *s1,const char *s2);
- 比较两个字符串,返回: 0:s1==s2,1:s1>s2,-1:s1
- strcpy
- charstrcpy(charrestrict dst,const char *restrict src);
- 把src的字符串拷贝到dst
- restrict表明src跟dst不重合
- 返回dst
- 为了能链起代码
- 复制一个字符串
- chardst = (char)malloc(strlen(src)+1); //之所以加一是因为结尾会自带\0,所以需要多一个位置
- strcpy(dst,src);
- strcat
- char*strcat(char *restrict s1,const char *restrict s2);
- 把s2拷贝到s1的后面,接成一个长的字符串
- 返回s1
- s1必须具有足够的空间
- strchr
- 字符串中找字符
- char*strchr(const char *s,int c);表示从左边找过来
- charstrrchr(const chars,int c);表示从右边找过来
- 返回NULL则表示没有找到
- 如何寻找第二个?寻找第二个的方法:
p = strchr(p+1,'l');
printf("%s\n",p);
- strstr
- 在字符串中寻找单个字符的
- char* strstr(const char *s1,const char *s2);
- 在寻找的时候忽略大小写
- char*strcasestr(const char *s1,const char *s2);
#include
#include
size_tmylen(constchar*s)
{
intcnt=0;
intidx=0;
while(s[idx] !='\0' ){
idx++;
cnt++;
}
returncnt;
}
intmain(intargc,charconst*argv[])
{
charline[] ="Hello";
printf("strlen=%lu\n",mylen(line));
printf("sizeof=%lu\n",sizeof(line));
return0;
}
#include
#include
intmycmp( constchar*s1, constchar*s2)
{
//int idx = 0;
//while( s1[idx] == s2[idx] && s1[idx]!='\0' ){
// idx ++;
//}
while( *s1==*s2&&*s1!='\0'){
s1++;
s2++;
}
return*s1-*s2;
}
intmain(intargc, charconst*argv[])
{
chars1[] ="abc";
chars2[] ="abc";
printf("%d\n",mycmp(s1,s2));
printf("%d\n",'a','A');
return0;
}
#include
#include
char*mycpy(char*dst, constchar*src)
{
intidx=0;
while(src[idx] !="\0"){
dst[idx] ==src[idx];
idx++;
}
dst[idx] ='\0';
// char* ret = dst;
// 方法1:while(*src != '\0'){
// *dst++ = *src++;
// }
//方法2:while(*dst++ = *src++); 嗯,没了,就一行直接替换掉了方法1,还有比方法1代码还有更长的版本我没有记录
// *dst = '\0'; 这是指针的写法
returndst;
}
intmain(intargc, charconst*argv[])
{
chars1[] ="abc";
chars2[] ="abc";
strcpy(s1,s2);
return0;
}
安全问题
- strcpy跟strcat都可能出现安全问题
- 如果目的地没有足够的空间?
- 建议是尽量不要去使用他
- 安全版本
- char* strncpy(charrestict dst, const char restrict src,size_t n);
- char* strncat(charrestict s1, const char restrict s2,size_t n);
- size_t n表示最多能够接受多少个n个字符,多了就直接掐掉
- int strncmp(const char *s1,const char *s2,size_t n);
- 这个则表示最多能够判断几个字符,超出则不判断
#include
#include
intmain(intargc, charconst*argv)
{
chars[] ="hello";
char*p=strchr(s,'l');
printf("%s\n",p); //结果为llo
//寻找第二个的方法:
//p = strchr(p+1,'l');
//printf("%s\n",p);结果为lo
return0;
}
---------------------------------------------------
将起选取的内容拷贝到其他地方的方法
intmain(intargc, charconst*argv)
{
chars[] ="hello";
char*p=strchr(s,'l');
char*t= (char*)malloc(strlen(p)+1);
strcpy(t,p);
printf("%s\n",t);
free(t); // 申请来的空间记得释放掉哦
//这是将llo的字符拷贝走了
return0;
}
-------------------------------------------------------
将起选取的内容拷贝到其他地方的方法2版本
intmain(intargc, charconst*argv)
{
chars[] ="hello";
char*p=strchr(s,'l');
charc=*p;
*p='\0';
char*t= (char*)malloc(strlen(s)+1);
strcpy(t,s);
printf("%s\n",t);
free(t); // 申请来的空间记得释放掉哦
//这是将he的字符拷贝走了
return0;
}