二、一维数组(字符类型)
字符类型的数组和其他类型的数组,在语法上是完全一样的。
但是字符类型的数组多了一种用法,它可以用来存储字符串。所以接下来我们主要讲字符串。
1. 字符串(常量):
羊肉和羊肉串有什么区别?羊肉串有签子,成串了。所以不是所有的羊肉都叫羊肉串。
有很多字符放在一起就是字符串吗?不是的!将很多字符顺序排列,最后以字符’\0’做结尾,才叫字符串。
在C语言中字符串常量必须由"“包含,当由”"包含字符串时,系统会默认在尾部加上’\0’
“hello world” 是字符串常量,系统会在尾部自动补上'\0' 一共有12个字符,'\0'是字符串中不可缺少的字符
“w” 是字符串常量,2个字符,'w' '\0'
"" 是字符串常量,1个字符 '\0'
输出’\0’什么显式都没有。'\0’存在唯一的意义就是作为字符串的结尾。
#include <stdio.h>
int main()
{
printf("|");
printf("\0");//此时字符串中有两个'\0',一个是自己写的,一个是自动补的
printf("|\n");
return 0;
}
输出结果:
||
2. 字符串注意要点:
- ‘\0’ 是由c编译系统自动加上的。 只要写""就会补’\0’
- 字符串常量是由双引号引起来的。
- 在字符串部分,我们会接触两种长度:
1)字符串长度 计算字符串的长度,不算结尾的 ‘\0’ “hello” 字符串长度是5。
2)字符串占内存的大小(长度) 就是字符串在内存中移动占的字节数,要算’\0’,'\0’也是一个字符,只不过输出的什么都没有。“hello” 占内存6个字节。
3. 字符数组的初始化
可以使用字符串常量初始化字符数组
char s[] = "hello"; 默认初始化,数组s有6个元素,h e l l o \0,或者写成char s[] = {"hello"};
char a[] = {'h','e','l','l','o','\0'}; 默认初始化,a中存放的数据,因为有'\0',a和s完全等价
char b[] = {'h','e','l','l','o'}; 默认初始化,b数组有5个元素,b中的数据不是字符串,因为没有'\0'
char c[10] = {'h','e','l','l','o'}; 部分初始化,其他元素默认补0,c中数据是字符串,因为0就是'\0'
区分
0 整数零
'\0' 字符杠零 ,字符杠零就是整数零
'0' 字符零,就是一个普通字符,和上面两者没有关系,没有任何特殊的含义。
4. 输入输出
1)字符输入输出函数:
输入: getchar(); 从输入缓存输入一个字符 ,执行一次只能输入一个字符。
输出: putchar(); 向输出缓存,输出一个字符
示例:
#include <stdio.h>
int main()
{
char a;
a = getchar();//输入一个字符,将输入的字符放在变量a中。
putchar(a);//输出一个字符
putchar('\n');//再输出一个\n
return 0;
}
遍历字符串示例:
遍历字符串,以’\0’作为字符串的结尾。
#include <stdio.h>
int main()
{
char a[100] = "hello";//使用字符串常量初始化字符数组a
int i = 0;
//使用循环遍历数组元素,遇到'\0'停止遍历,因为'\0'是字符串的结尾标识
while(a[i] != '\0')
{
putchar(a[i]);
i++;
}
putchar('\n');
//或者
/*
for(i = 0;a[i] != '\0';i++)
{
putchar(a[i]);
}
putchar('\n');
*/
return 0;
}
2)字符串输出输入函数:
get string
输入: gets();
相当于scanf("%s")
put string
输出: puts();
相当于printf("%s")
示例:
#include <stdio.h>
int main()
{
char buf[100];//字符数组用于存放我们输入的字符串
printf("gets输入\n");
gets(buf);//将输入的字符串放到数组buf中
printf("puts输出\n");
puts(buf);//输出数组buf中存放字符串,会在输出后自动加\n
printf("scanf 输入\n");
scanf("%s", buf);//将输入的字符串放到数组buf中,scanf输入字符串时,遇到空格结束
printf("printf输出\n");
printf("%s\n", buf);//输出数组buf中存放字符串
return 0;
}
scanf()现象:
>>helle word
hello
gets()现象:
>>helle word
helle word
字符数组编程示例1:
计算字符串长度。 char s[] = “Struggle for a better future”;
字符串长度不算\0
#include <stdio.h>
int main()
{
char buf[100] = "struggle for a better future";
int i;//用于遍历字符串
//int count = 0;//用于计数
for(i = 0;buf[i] != '\0';i++)//遍历字符串
{
//count++;//由于count和i的初始状态以及变化规律都一样,所以使用i代替count
}
//printf("%d\n", count);
printf("%d\n", -i);
return 0;
}
字符数组编程示例2:
统计字符串中有多少个 ‘e’ char s[] = “Struggle for a better future”;
#include <stdio.h>
int main()
{
char buf[100] = "struggle for a better future";
int i = 0;//用于遍历字符串
int count = 0;;//用于计数
while(buf[i] != '\0')
{
if(buf[i] == 'e')
{
count++;
}
i++;
}
printf("%d\n", count);
return 0;
}
三、字符串处理函数
//需要包含下面的头文件
#include <string.h>
4个字符串操作函数他们的原理都很重要,他们都是字符串的基本操作。
1. 求字符串长度的函数:
string length
int strlen( const char *string );
参数:存放字符串的数组名或者字符串常量
返回值:字符串长度,字符串长度不包含'\0'
#include <stdio.h>
#include <string.h> //字符串处理函数的头文件
int main()
{
char s[100] = "future";//使用字符串常量初始化数组s
int n = strlen(s);//将数组名作为参数传给strlen函数,会计算出s中字符串的长度
printf("%d\n",n); //6
printf("%d\n", strlen("hello world"));//将字符串常量作为参数传给strlen,直接打印返回值 11
return 0;
}
原理
#include <stdio.h>
int main()
{
char s[] = "hello world";
int i = 0;
while(s[i] != '\0')
{
i++;
}
printf("%d\n", i);
}
2. 字符串拷贝函数:
string copy
char *strcpy( char *strDestination, const char *strSource );
参数1:目标数组的数组名,要把字符串拷贝到这个数组里,我们自己保证数组得够长。
参数2:要拷贝的字符串,可以是存放字符串的数组名,也可以是字符串常量
返回值:参数1
#include <stdio.h>
#include <string.h>
int main()
{
char a[100];//数组a用来存放字符串
strcpy(a, "Tony");//参数2使用了字符串常量,将"Tony"拷贝到数组a中
printf("%s\n",a);//%s是以字符串形式输出a的数据 Tony
return 0;
}
原理
#include <stdio.h>
int main()
{
char a[100];//将s中的字符串拷贝到a中
char s[] = "hello world";
int i = 0;
while(s[i] != '\0')//遍历字符串s
{
a[i] = s[i];//将s中的i元素赋值给a的i元素
i++;
}
a[i] = '\0';//补'\0'
return 0;
}
示例引申:
#include <stdio.h>
#include <string.h>
int main()
{
char s1[20] = "hello\0 world";
printf("%s\n", s1);//hello %s表示打印字符串,任何字符串的操作都是到第一个\0结束
char name[20] = "hello world";
char a[200] = "Tony";
strcpy(name, "Tony");
printf("%s\n",name);//Tony
//此时name数组中的数据是什么样的?
//Tony\0 world\0\0\0\0
//以数组的形式遍历数组name,而不是以字符串形式遍历name
int i;
for(i = 0;i < 20;i++)
{
if(name[i] == '\0')//由于\0没有输出,所以使用NUL代替\0的输出
{
printf("NUL");
}
else
{
printf("%c", name[i]);//以字符形式正常打印数组中的元素
}
}
/*输出结果
TonyNUL worldNULNULNULNULNULNULNULNULNUL
*/
return 0;
}
3. 字符串连接函数:
string catenate
char\* strcat(char* strDestination, const char* strSource);
参数1:存放字符串的数组,保证长度够长。将字符串拼接到这个数组中存放的字符串的后面
参数2:要拼接到后面的字符串,可以是存放字符串的数组名,也可以是字符串常量。
返回值:参数1
#include <stdio.h>
#include <string.h>
int main()
{
char name[20] = "Hello ";//name必须保证空间还能放得下Tony
strcat(name, "Tony");//将Tony拼接到hello后面
printf("%s\n",name);//Hello Tony
return 0;
}
原理
#include <stdio.h>
#include <string.h>
int main()
{
char a[20] = "Hello ";
char b[] = "Tony";
//先找到数组a的'\0'位置
int i = 0;
while(a[i] != '\0')
{
i++;
}
//while(a[i] != '\0')循环停止的时候,i就是a的'\0'位置
//将b中的字符从a的'\0'位置逐个拷贝到数组a中,本例中使用T覆盖a中的'\0'
int j = 0;
while(b[j] != '\0')//遍历b的字符串
{
a[i] = b[j];//逐个拷贝b中的字符到a中
i++;
j++;
}
a[i] = '\0';//给a补'\0'
printf("%s\n", a);
//第一个循环是strlen的逻辑,第二个循环是strcpy的逻辑
return 0;
}
4. 字符串比较函数:
字符串比较,比较的是什么?
比较的是两个字符串中第一个不相等字符的ascii码值。
string compare
int strcmp( const char *src, const char *dst );
参数1:比较的第一个字符串,可以是存放字符串的数组名,也可以是字符串常量
参数2:比较的第二个字符串,可以是存放字符串的数组名,也可以是字符串常量
返回值:返回值不是表示真假的值
1 src > dst -1 src < dst 0 src == dst
#include <string.h>
#include <stdio.h>
int main()
{
printf("%d\n", strcmp("hello", "hallo wiwowiwiwo"));
return 0;
}
原理
#include <stdio.h>
int main()
{
char s1[] = "hello";
char s2[] = "hello world";
int i = 0;
while(s1[i]==s2[i] && s1[i]!='\0' && s2[i]!='\0')
{
i++;
}
if(s1[i] != s2[i])
{
printf("%d\n", s1[i]-s2[i]);
}
else
{
printf("0\n");
}
return 0;
}
strcpy和strcat返回值示例:
#include <stdio.h>
#include <string.h>
int main()
{
char buf[100];
strcpy(buf, "hello");
strcat(buf, " world");
printf("%s\n", buf);
//printf("%s\n",strcat(strcpy(buf, "hello"), " world"));
return 0;
}