C语言(四)字符串与字符数组
字符串与字符数组
字符和字符串
字符
- 普通字符:‘a’,‘1’
- 转义字符:’\a’,’\n’…
字符串
- “Boy”,”Maye”
字符与字符串的区别
1,形式上不同 c风格字符串 以\0结尾的字符串
2,本质上:字符串有结束符 ‘\0’
字符A和字符串A所占内存空间不一样,以下代码输出分别是多少呢?
printf("%d %d", sizeof('a'),sizeof("a"));
字符串与字符数组
特点:
- 字符数组可以没有’\0’
- 字符串必须要有’\0’
- 字符数组可以存储字符串
字符串一定是字符数组,字符数组不一定是字符串
下列字符数组存储的是不是字符串:
- char str[10] = {‘1’,‘b’,‘c’}; //是字符串,没有存满自动加了\0
- char str[1] ={’\0’}; //是字符串 等价于””
- “abcdedf”; //也是字符串,编译器会自动的在双引号最后加,上\0
- char str[10] =“abcdef"; //字符串可以用字符数组表示{‘a’,‘b’…’\0’}
- char str[10]={’‘a,”,”b”,”c”,’\0’} //不是字符串
- char *p=”maye”; //一个字符指针指向字符串
总结:
-
编译器不会给字符数组自动添加’\0’
-
编译器会自动给双引号的字符串字面值加上’\0’
-
指针指向的字符串是常量,是没法修改的。
字符数组的输入
getchar
char str[10];
for(int i=0;i<10;i++)
{
str[i] = getchar();
}
puts(str); //如果结尾没有'\0',输出结果将不可预料,可以改为逐个字符输出
- 在结尾自动加上’\0‘
for(int i=0;i<10;i++)
{
str[i] = getchar();
if(str[i] == '\n')
{
str[i] = '\0';
break;
}
}
scanf
- 使用scanf输入字符串时,遇到空格会自动截断,遇到回车结束,自动添加’\0’
- 输入超出范围时,不会进行越界检查,甚至能完全输出
gets_s
- 能读取空格,遇到回车结束,自动添加’\0’
- 输入超出范围时,会进行越界检查,如下图
为啥printf、puts能输出字符串?
由于C语言中没有真正的字符串类型,可以通过字符数组表示字符串,因为它的元素地址是连续的,这就足够了。
(1)从首地址开始逐字节寻址,把存储单元(一个字节)内的数据转换为ASCII字符格式输出。
(2)直到某一个字节内存的元素为字符’\0’时,输出此字符并且寻址结束。
如果字符数组里没有’\0’,那么使用printf (%s) 输出时,就找不到正确的结束标志,就会多输出一些乱码。
字符串处理函数
strlen
int strlen ( const char *str )
- 求字符串长度(不包括\0),注意和sizeof的区别
strlen("hello maye");
strcpy/strncpy
char *strcpy( char *dest, const char *src )
- 把一个src拷贝到dest中去,要保证dst缓冲区有足够的内存
- strcpy 会在dest结尾添加\0
- strncpy 不会在dest结尾添加\0
char dest[10];
strcpy(dest, "maye");
puts(dest);
strcmp/strncmp
int strcmp( char *str1, char *str2 )
- 比较str1和str2,str1>str2 返回1,str1==str2 返回0,否则返回-1
int res = strcmp("maye", "maye");
printf("res:%d\n", res);
strcat/strncat
char *strcat(char *dest, const char *src)
- 把src连接到dest的末尾(\0的位置)
char dest[20]="hello ";
strcat(dest, "maye");
puts(dest);
strchr/strrchr
char* strchr(char* _String, int _Ch)
- 在字符串string中查找字符val,存在返回val的开始位置,否则返回NULL
char words[] = "hello every one,My name's maye";
puts(strchr(words, 'o'));
strstr
char* strstr(char* _String, char * _SubString)
- 在字符串string中查找子串substr,存在返回substr的开始位置,否则返回NULL
char words[] = "hello every one,My name's maye";
puts(strstr(words, "one"));
memcmp
int memcmp( void const* _Buf1, void const* _Buf2,size_t _Size);
- 内存比较,不仅可以比较字符串,还可以比较其他的内存
int arr[5] = { 1,2,6,4,5};
int arr1[5] = { 1,2,5,4,5 };
int ok = memcmp(arr, arr1, sizeof(int) * 5);
int ok1 = strcmp(arr, arr1);
printf("%d %d\n", ok,ok1);
memcpy
void* memcpy( void* _Dst, void const* _Src, size_t _Size);
- 内存拷贝
int temp[5];
memcpy(temp, arr,sizeof(int)*5);
//strcpy(temp, arr); //复制整型数组会有问题,不知道什么时候结束
for (int i = 0; i < 5; i++)
{
printf("%d ", temp[i]);
}
memset
void* memset( void* _Dst, int _Val,size_t _Size);
- 按字节对内存进行初始化
char num[5];
memset(num, 127, sizeof(char) * 5);
for(int i = 0; i < 5; i++)
{
printf("%d ", num[i]);
}
sprintf
int sprintf(char *buffer, char *format [,argument,…]);
sprintf和printf类似,但不是打印到控制台,而是将内容作为 C字符串存储在buffer指向的缓冲区中。 缓冲区的大小应该足够大以包含整个结果字符串。 终止空字符\0
会自动附加在内容之后。
int main()
{
char str[50] = { 0 };
sprintf(str, "%s is %d years old!", "顽石", 18);
printf("%s", str);
return 0;
}
sscanf
int sscanf(char *buffer, char *format [,argument,…]);
从buffer读取数据,并根据参数格式将他们存储到由附加参数给出的位置,就像使用了scanf一样。
int main()
{
char str[] = "maye is 18 years old";
char name[10] = { 0 };
int age = 0;
//从字符串中获取姓名和年龄
sscanf(str, "%s %*s %d", name, &age);
printf("%s %d\n", name, age);
return 0;
}
- 点赞
- 收藏
- 关注作者
评论(0)