字符:
在计算机中字符都是以整理形式存储的,当需要显示时根据ASCII表中的对应关系显示出相应的符号和密度
'\0' 0
'0' 48
'A' 65
'a' 97
串:
是一种数据结构,是由一组连续的相同类型若干个数据组成,末尾有结束标志
对这种数据结构进行处理都是批量性处理,从开头位置到结束标志为止。
字符串:
由字符组成的串行结构,他的结束标志是'\0'
字符串的输入:
char str[256];
scanf (“%s”, 地址) //自带/0,回车即停止
注意:不能接收空格
char *gets(char *s);
功能:输入字符串到s中,可以接收空格
返回值:链式调用
注意:gets及scanf printf 不检查长度,不接收长度,会一直存储,会覆盖掉后面的额内容。输入超过定义长度后依旧输出
链式调用:把一个函数的返回值,作为另一个函数的参数
gets(str) = printf("%s", gets(str));
#include <stdio.h>
int main(int argc,const char* argv[])
{
char user[20] = {};
char pass[20] = "1234";
gets(user);
printf("%s",pass);
}
虽然定义的密码是“1234”,但是因为输入唱过20个字符,gets不接收长度,一直存储数据,因为user[20]和pass[20]是连续的,覆盖掉了pass的内容。
char *fgets(char *s, int size, stdin); //stdin是固定的意思
fgets(str,size,stdin)
例:fgets(user,20,stdin);//接收输入的19个,留一个给\0
功能:可以设置输入的字符串的长度为size-1,超出长度时会在末尾给'\0'预留位置,超出部分会不接收
注意:如果长度不足size-1,则会接收最后输入的'\n'换行
输入缓冲区:
程序并不会立即获取在终端输入的数据,先由终端保管。当按下回车时程序才会从输入缓冲区中读取数据
1、当读取的是整型或者浮点型数据时,而缓冲区中的数据是字母或符号时,此时从缓冲区获取数据失败,并不会从缓冲区中拿走字母或字符,数据会残留在输入缓冲区中,就会影响接下来的数据的读取
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
printf("%d %d %d\n",a,b,c);
当输入字母时,获取数据失败,导致数据残留在缓冲区,影响接下来的输入
int a,b,c;
while(3 > scanf("%d%d%d",&a,&b,&c))
{
printf("输入的数据格式有误,请重新输入:");
stdin->_IO_read_ptr = stdin->_IO_read_end;
}
printf("%d %d %d\n",a,b,c);
解决方法:根据scanf的返回值,判断变量是否从缓冲区内读取成功,如果失败则先清空缓冲区再重新输入
stdin->I0_read_ptr = stdin>IO_read_end;//跳过所有垃圾数据 ,_IO_read_ptr是一个指针,指向ptr指向当前要读的位置即开头,挪到末尾end,即跳过中间的数据
注意:只能在LIUNX系统上使用,把缓冲区的当前位置指针移动到缓冲区末尾,相当于清理缓冲区
2、fgets可以指定读取size-1个字节,如果超出范围,则多余的字符会残留在输入缓冲区中,会影响接下来的读取
char str[20] = {};
fgets(str,20,stdin);
char str2[20] = {};
scanf("%s",str2);
puts(str);
puts(str2);
输入的元素长度不够时则会自动接收最后输入的‘\n’,fgets的特性
输入的元素长度超过规定的长度时。会将在缓冲区的数据自动scanf存入输入中
char str[20] = {};
fgets(str,20,stdin);
char str2[20] = {};
scanf("%*[^\n]");
scanf("%*c");
scanf("%s",str2);
puts(str);
puts(str2);
输入中“%※”丢弃接下来输入的,叫做字符输入格式化,^取反的意思,
“%*[^\n]”的意思就是会一直丢弃字符到遇到回车时停止
“%*c”的意思就是丢弃一个字符类型
char str[20] = {};
fgets(str,20,stdin);
int len = 0;
while(str[len]) len++;
if('\n' != str[len-1])
{
scanf("%*[^\n]");
scanf("%*c");
}
char str1[20] = {};
scanf("%s",str1);
puts(str);
puts(str1);
解决方法:
判断fgets读取到的字符串的最后一个字符是否是\n,如果不是则说明缓冲区内有残留数据,才需要清理,必须确保缓冲区内有垃圾数据,否则程序会停下来等待接收一个\n
因此可以再清理缓冲区前,判断str末尾是不是\n,是则不用清理,否则需要清理
scanf(%*[^\n]"); 表示从缓冲区中读取并丢弃数据,只要不是\n就一直丢弃,遇到\n停止
scanf(“%*c”); 从缓冲区中读取并丢弃一个字符数据,也就是丢弃剩余的\n
注意:当不超过规定的长度时,会出现需要多输入一行的错误
3、当先输入的是整型或浮点型时,再输入字符、字符串时,会读取到上一次最后输入的残留的’\n’,会影响字符、字符串的输入
int num = 0;
char ch = 0;
scanf("%d%c", &num, &ch);
printf("--%d--%c--\n", num, ch);
显示在输入100后敲回车,‘\n’被看做是字符输入,字符与scanf配合有问题
int num = 0;
char ch = 0;
scanf("%d%s", &num, &ch);
printf("--%d--%s--\n", num, ch);
表示字符串和scanf配合没有问题
int num = 0;
char ch = 0;
scanf("%d", &num);
gets(ch);
printf("--%d--%s--\n", num, ch);
‘\n’都没有读到就直接结束
注意:scanf("%s", str) 不会影响字符串的输入
gets(str) 残留的\n会影响字符串的输入
解决方法:
输入字符 scanf(" %c", &ch); %C前加空格,会顶掉上一句的‘\n’,上一句没有也没有影响
输入字符串 scanf("%d ",&num);//空格加在后面 gets(str);
字符串的输出:
printf %s 地址
int puts(const char *s); //const保护指针变量,指针时共享的
功能:输出一个字符串,会在末尾自动打印一个'\n',而printf不接收换行
返回值:成功输出的字符个数 (+1有一个'\0')
输出缓冲区:
程序输出的数据并不会立即写入到“文件”中,而是先存储在输出缓冲区中,只有满足一定的条件时才会写入到文件中。
1、遇到\n后悔刷新所有缓冲区的数据
#include <stdio.h>
#include<unistd.h>
printf("hello world!");
printf("hello world!\n");
for(;;);
sleep(3);
for(;;) ---- 加了‘\n’后可以输出,不加不会输出,一直死循环
sleep(3) —— 加了’\n’后可以立即输出,而不加会在3s后输出
printf("hello world!");
printf("hello world!");
sleep(3);
printf("hello world!\n");
会在3s后瞬间输出三条hello world,这就是输出缓冲区
2、当遇到输入语句时也会立刻刷新
例:printf
printf 第二个printf不会出现
而 printf
printf
scanf 第二个printf会出现
<unistd.h>
sleep() usleep()
3、程序结束时
4、当缓冲区满4k时
5、手动刷新 fflush(stdout)
缓冲区机制可以提高数据的读写速度,并且可以让低速的输入输出设备与高速的CPU能够协调工作。
字符串的存在形式:
字符数组
char str[n] = (‘a’,‘b’,‘c’,……);
由char类型组成的数组,要记得为’\0’预留位置,赋值的数量不要超过n-1,赋值较麻烦
但使用的是栈内存,数据是可以修改的
例:str[0] = ‘A’;,可以直接改值
#include <stdio.h>
int main(int argc,const char* argv[])
{
char str[5] = {'a','b','c','d'};
char str1[5] = {'a','b','c','d','e'};
printf("%s\n",str);
}
因为没有为‘\0’预留位置,没有结束标志,会一直找结束标志一直输出。
字符串字面值:
代码段,只读,修改会产生段错误,地址
“由双引号包含的若干个字符” 在末尾隐藏了一个'\0'
printf(“hello world”) = printf("%s", "hello world")
所以字符串字面值就是以地址形式存在的,数据存储在代码段text里,如果修改则会产生段错误。
char* str = "12341234";
str[0] = '0';
printf("%s", str); //产生段错误,无法更改字符串字面值。
printf("%d", sizeof(str)); // 输出为4,指针就是4
sizeof(str); 数组总字节数,与输入的字符串无关printf("%d", sizeof(“12341234”)); // 9
printf("%d", strlen(“12341234”)); // 8,字符串的大小
sizeof("strstr") 结果=字符个数+1;
char* str1 = "hehe"两个一模一样的字符串字面值在代码段中只会存在一份,str1和st2是同一个地址
char* str2 = "hehe"
但是两个一模一样的数值存放的地址不同
int num1= 10; int num2 = 10;
常用方式:
字符数值[] = "字符串字面值" char str[] = "hehe world";
【】空下会自动计算个数 sizeof(str);//输出11
会自动给'\0'.预留位置
赋值完成后字符串会存有两份,一份存储在代码段,另一份存储在栈内存(可修改)
char str[] = "hehe world";
char str1[] = "hehe world"; 地址不同
练习1、实现一个函数,判断字符串是否是回文串
#include <stdio.h>
#include <stdbool.h>
bool back(char* str)
{
size_t len=0;
while(str[len])
{
len++;
}
for(int i=0;i<len/2;i++)
{
if(str[i] != str[len-1-i])
return false;
}
return true;
}
int main(int argc,const char* argv[])
{
char str[4096]={}; //一页
//scanf("%s",str);
gets(str);
if(back(str))
{
puts("yes");
}
}
else
{
puts("NO");
}
2、实现一个函数,把一个数字字符串转换为整数“12345” 12345
#include <stdio.h>
int back(const char* str)
{
int num=0;
while(*str)
{
if('0' <= *str && '9' >= *str)
{
num = num*10 + *str -'0';
str++;
}
}
return num;
}
int main(int argc,const char* argv[])
{
char str[256]={};
printf("%d\n", back(gets(str)));
}
字符串常用的处理函数
#include <string.h>
strlen
size_t strlen(const char *s);
功能:计算字符串长度,结果不包括'\0'
对比sizeof二者的区别主要是以下四点:
1、sizeof()是运算符,strlen()是库函数 2、sizeof()在编译时计算好了,strlen()在运行时计算
3、sizeof()计算出对象使用的最大字节数,strlen()计算字符串的实际长度
4、sizeof()的参数类型多样化(数组,指针,对象,函数都可以),strlen()的参数必须是字符型指(传入数组时自动退化为指针)
具体而言,当参数分别如下时,sizeof返回的值表示的含义如下:数组——编译时分配的数组空间大小; 指针——存储该指针所用的空间大小(在32位机器上是4,64位机器上是8);
类型——该类型所占的空间大小; 对象——对象的实际占用空间大小; 函数——函数的返回类型所占的空间大小。函数的返回类型不能是void例子:
p=hello,strlen=5,sizeof=6
字符串hello的长度是5,但在字符串最后隐藏一个\0故sizeof是6。p1=hello\0,strlen=5,sizeof=7
这里\0主动结束了字符串长度的计算,但隐藏的\0仍然有意义,故此时字符串中存在两个\0。p2=hello\0,strlen=7,sizeof=8
这里的\转义了\,使得\0不再是一个整体,也不具有原来停止计算长度的作用而只是两个普通字符\和0。p3=hello\\0,strlen=6,sizeof=8
这里第一个\只转义了第二个\,使得第二个\不能再转义后面的\,此时\0这个整体仍然有结束的作用。p4 的结果:p4=hel\0lo,strlen=3,sizeof=7
strlen碰到\0停止输出和计算,所以结果是3。但sizeof不会停止而且两个\0都计算。p5 的结果:p5=hel\0lo,strlen=7,sizeof=8
第一个\转义了紧接的\,使得\0变成两个普通字符\和0,sizeof比strlen多计算一个\0。————————————————
版权声明:本文为优快云博主「ly_1115」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/ly_6699/article/details/89482591
strcpy
char *strcpy(char *dest, const char *src);
功能:把src拷贝到dest,相当给dest赋值
返回值:dest的首地址,链式调用
char *strncpy(char *dest, const char *src, size_t n);
只拷贝前n个字符
注意:数组离开初始化就只能一个一个赋值
strcat
char *strcat(char *dest, const char *src);
功能:把src追加到dest的末尾 相当于+=
返回值:dest的首地址,链式调用
char *strncat(char *dest, const char *src, size_t n);
只追加前n个字符
strcmp
int strcmp(const char *s1, const char *s2);
功能:比较s1和s2两个字符串,按照字典序比较,谁在前谁小,比较出结果立即返回返回值
s1 >s2 正数 s1 = s2 0 s1 <s2负数
int strncmp(const char *s1, const char *s2, size_t n);
· 只比较前n个字符
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc,const char* argv[])
{
char str[256] = "helloooooo";//范围给大一点
printf("strlen: %d\n",strlen(str));
// printf("strcpy: %s\n",strcpy(str,"world")); //拷贝过去只是把“hello”覆盖了,后面的“ooooo”被‘\0’阻隔了不显示了
printf("strncpy: %s\n",strncpy(str,"world",7));//拷贝只拷贝前n个字符时,只要不拷贝\0后面的字符也会打印出来,超出运行正常
//str = "world";
printf("strcat: %s\n",strcat(str,"12311111111111111111"));
// printf("strncat: %s\n",strncat(str,"123",1));
// printf("strcmp: %d\n",strcmp("aca","abcaaaaa"));
printf("strncmp: %d\n",strncmp("aca","abcaaaaa",1));
printf("atoi:%d\n",atoi("a123"));
}
const char *strstr(const char *haystack,const char *needle);
功能:查找haystack中是否存在needle
返回值:如果存在,则返回needle第一次在haystack中出现的位置,如果找不到,返回NULL
#include <stdio.h>
#include <string.h>
int main(int argc,const char* argv[])
{
// puts(strstr("hello world","lli")); //产生段错误
const char* str = strstr("hello world","lli");
if(NULL == str)
{
printf("没找到\n");
}
else
{
printf("找到了\n");
}
}
char *strchr(const char *s, int c);
功能:查找字符串S中是否存在c
返回值:如果存在返回C第一次在S中出现的位置,不存在返回NULL
int sprintf(char *str, const char *format, ...);
功能:把各种类型的数据输入到str中
返回值:字符串str的长度
#include <stdio.h>
#include <string.h>
int main(int argc,const char* argv[])
{
int num = 10086;
float f = 3.14;
char str[256]={};
int ret = sprintf(str,"num = %d\n",num);
printf("ret=%d\n",ret);
puts(str);
for(int i=0; str[i]; i++)
{
printf("%d ",str[i]);
}
}
void *memcpy(void *dest, const void *src, size_t n);
功能:从src拷贝N个字节到dest中
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc,const char* argv[])
{
int arr[5] = {1,2,3,4,5};
int* p = malloc(sizeof(int)*5);
memcpy(p,arr,sizeof(arr));//n小于5时再输出后面的为0,超出无影响
for(int i=0; i<5; i++)
{
//p[i] = arr[i];
printf("%d ",p[i]);
}
}
int memcmp(const void *s1, const void *s2, size_t n);
功能:比较两个内存块,按字节比较,n指前几个字符,字母典谁在前谁小
返回值:
s1 > s2 正数
s1 = s2 0
s1 > s2 负数
#include <stdio.h>
#include <string.h>
int main(int argc,const char* argv[])
{
char* str1 = "abc";
char* str2 = "abb";
int ret = memcmp(str1,str2,3);
printf("ret=%d\n",ret);
}
ret=1
#include <stdlib.h>
int atoi(const char *nptr)
功能:字符串转int类型
printf("atoi:%d\n",atoi("a123"));
把字符串“123”转换为数值123,”a123"转换为0,"12a3"转换为12
long atol(const char *nptr);
功能:字符串转long类型
long long atoll(const char *nptr)
功能:字符串转longlong类型
double atof(const char *nptr)
功能:字符串转double类型
#include<stdio.h>
int sscanf(const char *str, const char *format, ...);
功能:从str中解析出各种类型数据,成功读取到的变量个数
char* str = "1999:2:20";
int year month day
sscanf(str,"%d %d %d", year,month,day);//字符串内什么格式就怎么读
printf("%d%d%d", year,month,day);
考点
练习:自己实现strlen strcpy strcat strcmp 四个常用的字符串处理函数
#include <stdio.h>
#include <string.h>
#include <assert.h>
//#include <assert.h>
//void assert( int exp );
size_t str_len(const char* str)
{
assert(NULL != str);
const char* tmp = str; //str为首地址
while(*tmp) tmp++;//tmp指向末地址
return tmp - str;//相减即是字节长度
}
char* str_cpy(char* dest,const char* src)
{
assert(NULL != str && NULL != dest);//对来历不明的指针需要判断是否为空指针,用于错误检测,如果表达式结果为0,宏写错误信息到STDERR并退出程序执行,相当于断点
char* tmp = dest;
while(*tmp++ = *src++); //=是赋值运算符,把src的值赋给tmp,而==是关系运算符,是如果src=tmp会在怎么怎么样,当src=‘\0’,循环结束
return dest; //如果src的长度超过了dest的长度,则会报错产生段错误,src长度小于dest则没有问题
}
char* str_cat(char* dest,const char* src)
{
assert(NULL != str && NULL != dest);
char* tmp = dest; //备份首地址
while(*tmp) tmp++;//先走到末尾
while(*tmp++ = *src++);//再从末尾地址开始赋值,如果追加后的长度超过dest的长度,则报错产生段错误
return dest//返回首地址dest而不是返回末尾tmp
}
int str_cmp(const char* s1,const char* s2)
{
assert(NULL != s1 && NULL != s2);
while(*s1 && *s1 == *s2) s1++,s2++;
// return *s1 - *s2;
if(*s1 > *s2)
return 1;
if(*s1 < *s2)
return -1;
else
return 0;
}
int main(int argc,const char* argv[])
{
char str[256] = "hehe";
// printf("%d\n",strlen(NULL));
printf("strlen:%d\n",str_len(NULL));
printf("strcpy:%s\n",str_cpy(str,"ha"));
printf("strcat:%s\n",str_cat(str,"qqq"));
printf("strcmp:%d\n",str_cmp("abd","abc"));
}