一、字符串
字符:人能看的懂的符号或图案,在内存中以整数形式存储,根据ASCII码表中的对应关系显示出相应的符号或图案
串:是一种数据结构,存储类型相同的若干个数据
对于串行结构的处理是批量性的,会从头开始直到遇到结束标志停止(~0)
字符串:由字符组成的串行结构,结束标志是 '\0'
二、字符串的存在形式
字符数组:
由char组成的数组,注意要为'\0'预留位置,初始化麻烦
用的是栈内存,数据可以修改
char str[10] = {'a','b','c',...};
printf("%s\n",str);
字符串字面值:
"由双引号包含的若干个字符"
末尾会隐藏一个'\0',定义也方便
字符串字面值就是以地址形式存在的,是常量,存储在代码段中,不能修改,否则会发生段错误
注意:相同内容的多份字符串字面值,在代码段中只会存在一份
sizeof("xxxx") 计算出 字符个数+1
常用方式:
字符数组[ ] = "字符串字面值";
会自动为 '\0' 预留位置
注意:赋值完成后,该字符串在内存中有两份,一份在代码段,另一份在栈内存中(可修改)
三、字符串的输入和输出
输入:
// scanf("%s",地址);
// 缺点:不能输入空格
char str[100] = {};
scanf("%s",str);
printf("%s\n",str);
// char *gets(char *s);
// 返回值:s 链式调用
// 功能:输入字符串到s中,能够输入空格
// 缺点:有警告,输入的长度不受限制,有危险
char str[100] = {};
// gets(str);
printf("%s\n",gets(str));
// char *fgets(char *s,int size,FILE *stream);
// 功能:输入长度最多为 size-1 的字符串,会自动为'\0'预留位置
// 超出部分不接收,不足时最后的'\n'(回车)也会一起接受
char str[100] = {};
// fgets(str,10,stdin);
printf("%s\n",fgets(str,10,stdin));
输出:
// printf("%s",地址)
int puts(const char *s);
// 功能:输出一个字符串,并且会自动在末尾打印一个'\n'
// 返回值:成功输出的字符个数
四、输出缓冲区
缓冲区机制可以提高数据的读写速度,还可以让低速的设备与高速的CPU之间协调工作
程序要显示的数据并不会立即显示到屏幕上,而是先存储到输出缓冲区中,当满足一定条件时才会从输出缓冲区显示到屏幕上
1、遇到 '\n'
2、遇到输入语句
3、当缓冲区满了 4K
4、程序正常结束时
5、fflush(stdout); 手动刷新输出缓冲区
五、输入缓冲区
程序中输入的数据并不会立即从键盘接收到变量中,而是当按下回车后,先存储到输入缓冲区中,然后再从缓冲区中读取到变量内存中
情况1:需要输入的是整型\浮点型时,而缓冲区中的数据是字符型或符号时,此时读取会失败,并且该数据会继续残留在输入缓冲区中,会继续影响剩下的输入
解决:根据scanf的返回值判断输入是否有问题,如果读取失败,则先清理输入缓冲区后重新输入直到读取成功为止
while(3 != scanf("%d%d%d",&a,&b,&c))
{
stdin->_IO_read_ptr = stdin->_IO_read_end;
// 把输入缓冲区的位置指针从当前位置,移动到末尾相当于清理输入缓冲区
// 注意:只能在Linux系统下使用
}
情况2:通过 fgets 可以指定读取 size-1个 字符,但是如果输入超过 size-1 个,字符会残留在输入缓冲区中,继续影响接下来的输入
解决:判断字符串的最后一个字符是否是'\n',如果不是,说明缓冲区中有残留
// 方法1
int len = 0;
while(str[len]) len++;// len是'\0'的下标
if('\n' != str[len-1])// '\0'前面不是'\n'则清理
{
scanf("%*[^\n]");
// 从缓冲区中读取任意类型数据并丢弃,直到遇到'\n'停止
scanf("%*c");
// 从缓冲区中读取任意字符类型数据并丢弃,清理'\n'
}
情况3:当先输入整型或浮点型,再输入字符形式,输入完整型或浮点型后按下的回车或空格,会残留在输入缓冲区,刚好被后面的字符型接收,影响输入
解决:在%c或者gets()前面加空格
scanf(" %c");
六、字符串相关函数
#include <string.h>
size_t strlen(const char *s);
// 功能:计算字符串的长度,不包括'\0'
// 返回值:返回字符个数
char str[100] = "hello";
printf("strlen=%d\n",strlen(str));// 字符个数
printf("size=%d\n",sizeof("hello"));// 字节数
#include <string.h>
char *strcpy(char *dest, const char *src);
// 功能:把src拷贝给dest,相当于给dest赋值
// 返回值:dest的首地址,链式调用
char str[100] = "hello";
printf("strcpy=%s\n",strcpy(str,"world"));
#include <string.h>
char *strcat(char *dest, const char *src);
// 功能:把src追加到dest的末尾,相当于+=
// 返回值:dest的首地址,链式调用、
char str[100] = "hello";
printf("strcat=%s\n",strcat(str,"world"));
#include <string.h>
int strcmp(const char *s1, const char *s2);
// 功能:比较两个字符串,根据字典序,谁出现早谁小,一旦比较出结果,立即返回
// 返回值:
// s1 > s2 正数
// s1 == s2 0
// s1 < s2 负数
printf("strcmp=%d\n",strcmp("abc","adc"));
#include <stdlib.h>
int atoi(const char *nptr);
// 功能:把字符串转换成int类型
#include <stdlib.h>
double atof(const char *nptr);
// 功能:把字符串转换成double类型
#include <string.h>
char *strstr(const char *haystack, const char *needle);
// 功能:在haystack中查找是否存在子串needle
// 返回值:needle在haystack中第一次出现的位置,如果找不到返回NULL
#include <stdio.h>
int sprintf(char *str, const char *format, ...);
// 功能:把任意类型的数据转换成字符串并输入到str中
int main(int argc,const char* argv[])
{
int num = 10086;
double d = 3.14;
char str[100] = {};
sprintf(str,"num=%d d=%lf\n",num,d);
printf("%s",str);
}
#include <stdio.h>
int sscanf(const char *str, const char *format, ...);
// 功能:从字符串中解析出各种类型的数据,并储存到对应的变量中
int main(int argc,const char* argv[])
{
char* str = "1997 7 1.11";
int year = 0,month = 0;
double d = 0;
sscanf(str,"%d %d %lf",&year,&month,&d);
printf("%d %d %lf\n",year,month,d);
}
#include <string.h>
void *memcpy(void *dest, const void *src, size_t n);
// 功能:把src内存的数据拷贝n个字节到desk中
int arr1[10] = {1,2,3,4,5,6,7,8,9,10};
int* p = malloc(40);
memcpy(p,arr1,40);// 拷贝的类型要相同
//memcpy/memmove/memset/memcmp(按字节比较)