一、一维字符数组思维导图
在C语言中,经常使用字符数组存储字符串,""引起来的都是字符串,
C语言中的字符串以'\0'结尾,'\0'看不到打印不出来
eg: "hello" ------> 实际占用6个Byte的空间
二、一维字符数组
2.1格式
char 数组名 {长度};
2.2初始化和赋值
#include <stdio.h>
int main(int argc, const char *argv[])
{
/**********字符数组的初始化和赋值***********/
char str[3]={'0','9','a'}; //完全初始化
char str1[6]="hello"; //使用字符串给字符数组初始化
char str2[]="hello"; //会根据初始化列表给字符数组分配空间
printf("%ld\n",sizeof(str2)); //6,因为会给'\0'分配空间
char str3[4]={"hi"};
/*****赋值*****/
str[2]='A';
printf("%c\n",str[2]);
//str="hello"; 报错
return 0;
}
2.3字符数组的输入和输出
一般使用字符数组都是存储字符串,所以对于字符数组的输入和输出,实际上是对字符串的输入和输出
字符数组的输入输出可以用格式符或者输入输出函数
2.3.1使用格式符输入输出
输入:
使用格式符%s完成对字符数组的输入
#include <stdio.h>
int main(int argc, const char *argv[])
{
char str[10];
//使用格式符完成对字符数组的输入
scanf("%s",str);
printf("str=%s\n",str);
return 0;
}
输出:
%s:用于字符串的输入输出,%s在输出时,需要字符串的首地址,从首地址开始输出字符串直到遇到'\0'结束 (如果字符数组中存储的是多个字符使用%c循环输出,如果字符数组中存储的是字符串%s直接输出字符串)
#include <stdio.h>
int main(int argc, const char *argv[])
{
/**********字符数组的初始化和赋值***********/
char str[3]={'0','9','a'}; //完全初始化
char str1[6]="hello"; //使用字符串给字符数组初始化
char str2[]="hello"; //会根据初始化列表给字符数组分配空间
printf("%ld\n",sizeof(str2)); //6,因为会给'\0'分配空间
char str3[4]={"hi"};
int i;
for(i=0;i<3;i++)
{
printf("%c\n",str[i]);
}
//printf("%s\n",str);
//str确实字符数组的首地址,但是str中存储的不是带有'\0'的字符串,
//不能使用%s输出,只能通过循环使用%c输出多个字符
printf("%s\n",str1); //str1存储的是hello字符串结尾有'\0'
printf("str=%p\n",str); //数组名就表示数组的首地址(第一个元素的地址)
printf("&str[0]=%p\n",&str[0]);
return 0;
}
2.3.2使用输入输出函数
(1)puts函数
用于输出字符串的函数
函数原型:
int puts(const char *s);
功能:从字符串的首地址开始输出字符串
参数:字符串的首地址
(2)gets函数
用于字符串的输入函数
函数原型:
char *gets(char *s);
功能:终端获取字符串
参数:字符串的首地址
要求:在使用gets完成字符串输入时,要控制终端输入的阿字符串,不能超出字符数组的长度
使用gets一定会报错,说的是函数是不安全的,因为gets不会检测字符串范围,即使输入的字符串过长也会放进字符数组中,但是会造成越界问题。
示例:
#include <stdio.h>
int main(int argc, const char *argv[])
{
char str[10];
gets(str); //使用gets给字符数组str输入
puts(str); //需要字符串的首地址,从首地址开始输出整个字符串
return 0;
}
三、数组越界
数组越界的错误不可预知,尽量在书写时不要出现数组越界的问题
四、字符串函数族的函数
如果要使用字符串函数族中的函数,需要导入头文件
(1)strlen函数
函数原型:
size_t strlen(const char *s);
返回值:字符串的大小
参数:字符串的首地址
功能:计算字符串不包含'\0'的长度
执行逻辑:
获取到字符串的首地址后,从首地址开始,记录字符串的长度遇到'\0',函数停止运行。
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{
char str[100];
gets(str);
printf("%ld\n",strlen(str)); //11字符串不包含'\0'的大小
return 0;
}
自己实现strlen函数
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{
char str[100];
gets(str);
int len=0;
int i=0; //定义了一个循环变量i从0开始
//自己实现strlen函数
while(str[i]!='\0')
{
i++; //循环字符数组中的每一个字符
len++; //记录字符数组的长度
}
printf("%d\n",len);
return 0;
}
(2)strcpy函数
注意:
使用strcpy函数时,目标数组必须足够长,容纳下源数组中的内容。
dest数组必须足够长,容纳下src数组中的内容
函数原型:
char *strcpy(char *dest, const char *src);
返回值:目标字符串的首地址
参数:dest数组的首地址,src数组的首地址
功能:将src数组中的内容跟,拷贝到dest数组中覆盖掉dest原有的内容
执行逻辑:
从src数组的首地址开始,将每一个数组中的元素拷贝到dest数组中对应下标的位置,直到遇到'\0',将'\0'拷贝过去后,结束
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{
char str[100]="hello";
char str1[20]="hello world";
strcpy(str,str1); //使用strcpy函数,将str1字符串拷贝到str中
puts(str);
return 0;
}
自己实现strcpy函数
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{
char str[100]="hello";
char str1[20]="hi";
int i=0;
//拷贝要保证源字符串的每一位都拷贝到目标字符串中
//循环应该保证源字符串的每一位都进入循环
while(str1[i]!=0)
{
str[i]=str1[i];
i++; //第i位拷贝结束后,继续拷贝第i+1位
}
//退出while循环时,说明str1走到了'\0'
//再将'\0'赋值给str的第i位
str[i]=str1[i]; //赋结尾的'\0'
puts(str);
return 0;
}
(3)strcat函数
目标字符串一定要足够长容纳下strcat拼接后的结果。
函数原型:
char *strcat(char *dest, const char *src);
dest表示目标字符串,src表示源字符串
返回值:目标字符串的首地址
参数:目标字符串的首地址,源字符串的首地址
执行逻辑:
从源字符串的首地址出发,将源字符串中的每一个字符拼接到目标字符串的后面。
如果自己实现步骤:
1、找到目标字符串'\0'的位置
2、从目标字符串'\0'的位置开始,将源字符串中的每一位拼接过去
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{
char str[20]="hello";
char str1[10]=" world";
//将str1数组,拼接到str数组后面
strcat(str,str1);
puts(str); //"hello world";
return 0;
}
自己实现strcat函数
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{
char str[20]="hello";
char str1[10]=" world";
//自己实现strcat
int i=0,j=0;
//1、找到目标字符串'\0'的位置
while(str[i]!=0)
{
i++;
}
//当退出循环时,str[i]=='\0'
//将源字符串中的每一位,拼接到目标字符串'\0'开始的每一个位置
while(str1[j]!='\0')
{
str[i]=str1[j];
i++;
j++;
}
//当第二个while循环退出时,说明源字符串也走到了'\0'
str[i]=str1[j];
puts(str);
return 0;
}
(4)strcmp函数
函数原型:
int strcmp(const char *s1, const char *s2);
返回值:ASCII码差值
参数:比较的字符串
执行逻辑:
从两个字符串的首元素开始比较,如果相同继续向后比较,直到'\0',这种情况下会返回0,如果遇到某一位不同,立刻返回ASCII码差值(s1[i]-s2[i])并结束函数。
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{
char str[10]="hello";
char str1[10]="hel";
printf("%d\n",strcmp(str,str1)); //108是,'l'-'0'的值
return 0;
}
自己实现
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{
char str[10]="hello";
char str1[10]="hel";
int i=0;
//判断何时两个字符串一直往下走找下一位
//当两个字符串下标为i的位置相等,并且都不为0时
while(str[i]==str1[i]&&str[i]!=0) //'\0'的ascii码就是0
{
i++; //向后比较下一位
}
//如果不满足循环条件,说明两个字符串的第i位不相等
//或者是两个字符串的第i位相等,但是都是'\0'
int ret = str[i]-str1[i];
printf("%d\n",ret);
return 0;
}
(5)memset函数
用作内存置位(以字节为单位进行内存置位)
函数原型:
void *memset(void *s, int c, size_t n);
返回值:地址
参数:要置位的起始地址,要置什么数值,置多少个字节
功能:给指定地址开始的n个字节内的,数据置为c
(6)bzero函数
内存置0,以字节为单位
函数原型:
void bzero(void *s, size_t n);
返回值:地址
参数:要置位的起始地址,要置多少个字节
功能:给内存置0
五、二维字符数组
5.1格式
int arr[行数][列数];
5.2访问数组中的元素
通过行标和列标去访问
数组名[行标][列标];
行标最小为0,最大为:行数-1
列标最小为0,最大为:列数-1
二维数组中元素的个数=行数*列数
5.3二维数组的初始化和赋值
#include <stdio.h>
int main(int argc, const char *argv[])
{
int arr[2][3]={1,2,3,4,5,6}; //类似于一维数组的完全初始化方式
//二维数组以行为单位的初始化并且是不完全初始化,未初始化的部分默认为0
int arr1[2][3]={
{1,2},{4,9}};
//二维数组省略行数的初始化
int arr2[][2]={1,2,3,4,5};
printf("%ld\n",sizeof(arr2));
//int arr3[2][]={1,2,3,4,5};
//error二维数组不能省略列数初始化,只能省略行数初始化
arr1[0][2]=3; //给arr1数组中第一行第三列的元素赋值为3
return 0;
}