复习:
堆内存管理:
C语言没有管理堆内存的语句,只能使用标准库的函数
#include <stdio.h>
void* malloc(size_t size);
注意:void* 在C++编译器中是不能自动转换成其他类型的指针,如果想让代码也在C++编译器中兼容,需要强制类型转换
int* p =(int*)malloc(4);
注意:C编译器不允许在main函数之前调用函数,但C++允许
void free(void* ptr);
注意:不要重复释放,不要释放非法地址,但是可以释放NULL
*常考的笔试面试题:
1、堆内存和栈内存的区别
是什么?优缺点比较?使用注意事项
2、堆内存越界的后果?
没超过33页可能脏数据过一切正常,超了33页一定段错误
越界破坏了malloc的维护信息,当再次free时会内存崩溃
3、什么是内存泄漏,如何定位内存泄漏
由于业务逻辑有问题或粗心大意导致已经使用完毕的堆内存没有释放,当需要时再次申请,又继续没有释放,长期以往内存就会越来越少,系统就会慢慢卡死或崩溃,这种就叫做内存泄漏
1、查看进程内存情况 ps -aux
2、通过mtrace类似的代码
3、重新封装malloc和free,记录调用情况到日志中
4、什么是内存碎片,如何减少产生内存碎片
已经释放但是无法使用的内存,一般由于申请和释放的时间、大小不协调导致的
1、尽量使用栈内存
2、不要频繁地申请和释放
3、申请大块内存自己管理
----------------------------------------------------------
一、字符串
字符:人能看的懂的符号或图案,在内存中以整数形式存储,根据ASCII码表中的对应关系显示出相应的符号或图案
'\0' 0 空字符
'0' 48
'A' 65
'a' 97
串:是一种数据结构,存储类型相同的若干个数据
对于串型结构处理是批量性的,会从头开始知道遇到结束标志停止
字符串:
由字符组成的串型结构,结束标志是'\0'
二、字符串的存在形式
字符数组:
char str[10]={'a','b','c',...};
由char组成的数组,注意要为'\0'预留位置,初始化麻烦
使用的是栈内存,数据可以修改
字符串字面值:
"由双引号包含的若干个字符"
末尾会隐藏一个'\0',定义方便
字符串字面值就是以地址形式存在的,是常量,存储在代码段中,不能修改,否则段错误
注意:相同内容的多份字符串字面值,在代码段只会存在一份
注意:sizeof("xxxxxxx")计算出字符个数+1
常用方法:
字符数组[]="字符串字面值";
会自动为'\0'预留位置
注意:赋值完成后,该字符串在内存中有两份,一份在代码段,另一份在栈内存(可以修改)
三、字符串的输入和输出
scanf %s 地址
缺点:不能输入空格
char* gets(char* s);
功能:输入字符串到s中,能够输入空格
返回值:s 链式调用
缺点:有警告,输入的长度不受限制,有风险
char* fgets(char* s,int size,FILE* stream);
功能:输入长度最多为size-1的字符串,会自动为'\0'预留位置
超出部分不接受,不足是最后的'\n'也会一起接受
输出:
printf %s 地址
int puts(const char* s);
功能:输出一个字符串,并且会自动在末尾打赢一个'\n'
功能:成功输出的字符个数
练习1:实现一个函数,判断一个字符串是不是回文字符串
四、输出缓冲区
缓冲区机制可以提高数据的读写速度,还可以让低速的设备与高速的CPU之间协同工作
程序要显示的数据并不会立即显示到屏幕上,而是先存储到输出缓冲区中,当满足一定条件时才会从输出缓冲区显示到屏幕上
1、遇到'\n'
2、遇到输入语句 测试scanf("%*c");
3、当缓冲区满了 一般是4k
4、当程序正常结束时
5、fflush(stdout);手动刷新输出缓冲区
五、输入缓冲区
程序中输入的数据并不会立即从键盘接收到变量中,而是当按下回车后先存储到输入缓冲区中,然后再从缓冲区中读取到变量内存中
情况1:需要输入的是整形/浮点型时,而缓冲区中的数据是字符型或符号时,此时读取会失败,并且该数据会继续残留在输入缓冲区中,会继续影响剩下的输入
解决:根据scanf的返回值判断输入是否有问题,如果读取失败,则先清理输入缓冲区后重新输入,知道读取成功为止
情况2:通过fgets可以指定读取size-1个字符,但是如果输入超过size-1那么字符会残留在输入缓冲区中,继续影响接下来的输入
方法一:
if('\n'!=str[strlen(str)-1])strlen(str)是'\0'的下标,'\0'前面不是'\n'则清理
{
scanf("%*[^\n]"); //从缓冲区中读取任意数据并丢弃,直到遇到'\n'停止
scanf("%*c"); //从缓冲区中读取任意字符类型数据并丢弃
}
方法二:
stdin->_IO_read_ptr=stdin->_IO_read_end;
//把输入缓冲区的位置指针从当前位置,移动到末尾,相当于清理输入缓冲区
注意:只能在Linux系统下用
情况3:当先输入整形/浮点型,再输入字符型时,输入玩整形或浮点型后按下的回车或空格,会残留在输入缓冲区,刚好被后面的字符型接收,影响输入
解决:在%c或者gets()前面加空格
scanf(" %c");
六、字符串相关函数
#include <string.h>
size_t strlen(const cahr* s);
功能:计算字符串的长度,不包括'\0'
char* strcpy(char* dest,const char* src);
功能:把src拷贝给dest,相当于给dest赋值=
返回值:dest的首地址,链式调用
char* strcat(char* dest,const char* src);
功能:把src追加到dest末尾,相当于+=;
返回值:dest的首地址,链式调用
int* strcmp(const char* s1,const char* s2);
功能:比较两个字符串,根据字典序,谁先出现谁小,一旦比较出结果就立即返回结果
返回值:
s1>s2 正数
s1==s2 0
s1<s2 负数
char* strncpy(char* dest,const char* src,size_t n);
char* strncat(char* dest,const char* src,size_t n);
int* strncat(const char* s1,const char* s2,size_t n);
int atoi(const char* nptr);
功能:把字符串转换成int类型
double atof(const char* nptr);
功能:把字符串转换成float类型
char* strstr(const char* haystack,const char* needdle);
功能:把haystack中查找是否存在子串needle
返回值:needle在haystack中首次出现的位置,如果找不到返回NULL
int sprintf(char* str,const char* format,...) ;
功能:把各种类型的数据转化成字符串并输入到str中
int sscanf(const char* str,const char* format,...) ;
功能:从字符串中解析出各种类型的数据,并且存储到对应变量中
void* memcpy(void* dest,const void* src,size_t n);
功能:把src内存的数据拷贝n个字节到dest中