首页 > 其他分享 >c语言学习9

c语言学习9

时间:2023-07-26 21:12:26浏览次数:36  
标签:__ char const 语言 学习 缓冲区 字符串 输入

一、字符串
字符:人能看得懂的符号或图案,在内存中以整数形式存储,根据ASCII码表中的对应关系显示出相应的符号或图案
'\0' 0 空字符
'0' 48
'A' 65
'a' 97

串:是一种数据结构,存储类型相同的若干个数据
    对于串型结构的处理是批量性的,会从头开始直到遇到结束标志停止

字符串:
    由字符组成的串型结构,结束标志是 '\0'

二、字符串的存在形式
字符数组:
char str[10] = {'a','b','c',...};
由char组成的数组,注意要为'\0'预留位置,初始化麻烦
使用的是栈内存,数据可以修改

字符串字面值:
    "由双引号包含的若干个字符"
    末尾会隐藏一个'\0',定义也方便
    字符串字面值就是以地址形式存在的,是常量,数据存储在代码段中,不能修改,否则段错误
    注意:相同内容的多份字符串字面值,在代码段中只会存在一份
    注意:sizeof("xxxx") 计算出 字符个数+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:实现一个函数,判断一个字符串是否是回文串
    "abccba" 

四、输出缓冲区
缓冲区机制可以提高数据的读写速度,还可以让低速的设备与高速的CPU之间系统工作
程序要显示的数据并不会立即显示到屏幕上,而是先存储到输出缓冲区中,当满足一定条件时才会从输出缓冲区显示到屏幕上
1、遇到'\n'
2、遇到输入语句
3、当缓冲区满了4k
4、程序正常结束时
5、fflush(stdout); 手动刷新输出缓冲区

五、输入缓冲区
程序中输入的数据并不会立即从键盘接收到变量中,而是当按下回车后先存储到输入缓冲区中,然后再从缓冲区中读取到变量内存中

情况1:需要输入的是整型\浮点型时,而缓冲区中的数据是字符型或符号时,此时读取会失败,并且该数据会继续残留在输入缓冲区中,会继续影响剩下的输入
    解决:根据scanf的返回值判断输入是否有问题,如果读取失败,则先清理输入缓冲区后重新输入,直到读取成功为止,可以设置一个清楚函数,使用int n;while((c=getchar())!='\n'&&c!=EOF));来实现对输入缓冲区的清空。

情况2:通过fgets可以指定读取size-1个字符,但是如果输入超过size-1那么字符会残留在输入缓冲区中,继续影响接下来的输入
    解决方法1:
    int len = 0;
    while(str1[len]) len++; //len是'\0'的下标
    if('\n' != str1[len-1])// '\0'前面不是'\n'则清理
    {    
        scanf("%*[^\n]");
    //从缓冲区中读取任意类型数据并丢弃,直到遇到'\n'停止
        scanf("%*c");
    //从缓冲区中读取任意字符类型数据并丢弃
    } 
    解决方法2:
    void clear_input_buffer() {
        int ch;
        while ((ch = getchar()) != '\n' && ch != EOF);

}
方法3:
stdin->_IO_read_ptr = stdin->_IO_read_end;
// 把输入缓冲区的位置指针从当前位置,移动到末尾,相当于清理输入缓冲区
注意:只能在Linux系统下使用

情况3:当先输入整型或浮点型,再输入字符型时,输入完整型或浮点型后按下的回车或空格,会残留在输入缓冲区,刚好被后面的字符型接收,影响输入
    解决:在%c或者gets()前面加空格
        scanf(" %c");

六、字符串相关函数
#include <string.h>
size_t strlen(const char *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);   //它用于将一个字符串(src)的前 n 个字符复制到另一个字符串(dest)中
char *strncat(char *dest, const char *src, size_t n);   //用于将一个字符串(src)的前 n 个字符连接(追加)到另一个字符串(dest)的末尾
int strncmp(const char *s1, const char *s2, size_t n);  //用于比较两个字符串(s1 和 s2)的前 n 个字符。

int atoi(const char *nptr);
功能:把字符串转换成int类型
double atof(const char *nptr);
功能:把字符串转换成double类型

char *strstr(const char *haystack,const char *needle);
功能:在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);    //请注意,如果源和目标内存区域重叠,memcpy 的行为是未定义的。在这种情况下,应使用 memmove 函数,因为它可以处理重叠的内存区域
功能:把src内存的数据拷贝n个字节到dest中

预处理指令的分类:
#include 头文件导入(拷贝)
#include <> 从系统指定路径查找头文件
#include "" 从当前工作路径查找,找不到再从系统指定路径查找
-I path 可以指定要查找的路径path
还可以通过设置环境变量来指定路径

#define 定义宏
    宏常量:
        #define MAX 50
        优点:提高代码可扩展性、提高可读性、提高了安全性、还可以与case配合
        注意:定义宏常量不要加分号,一般宏名全部大写
        预定义好的宏常量:
            printf("%s\n",__func__);    获取函数名
            printf("%s\n",__FILE__);    获取文件名
            printf("%d\n",__LINE__);    获取行号
            printf("%s\n",__DATE__);    获取日期
            printf("%s\n",__TIME__);    获取时间
    宏函数:
        是带参数的宏
        不是真正意义的函数,没有发生传参,也没有返回值,也不会去检查参数的类型
        #define SUM(a,b) a+b
        1、先把在代码中出现了宏函数的位置,替换成宏函数后面的语句
        2、再把代码中使用的参数替换成调用者的参数
        注意:宏的内容必须保证在同一行,如果要换行,要在每一行的末尾添加续行符 \
    
    宏函数的二义性:
        由于宏函数代码位置、附近的值、参数各种原因的影响,会导致宏函数有不同的解释,这叫做宏的二义性
        如何避免宏的二义性:
            每个参数都加小括号,整体也叫小括号,不要在宏函数的参数中使用自变运算符

2、宏函数与普通函数的区别?
是什么?
普通函数:是一段觉有某项功能的代码集合,会被编译成二进制指令存储在代码段中,函数名就是它的首地址,有独立的栈内存

    宏函数:带参数的宏替换,不是真正的函数,用起来像函数,没有独立的栈内存
    有什么区别?
    函数:  返回值、类型检查、安全、入栈出栈调用、跳转、速度慢
    宏函数:运行结果、通用、危险、替换、冗余、速度快

条件编译:
    根据条件决定让代码是否参与最终的编译

    版本控制:
    #if 
    #elif 
    #else
    #endif

    头文件卫士:防止头文件被重复包含,头文件必加
    #ifndef 宏名    //如果宏不存在为真
    #define 宏名
    //
    #endif

    判断、调试:
    #ifdef 宏名 //如果宏存在为真
    #else
    #endif
    在编译时添加宏DEBUG:gcc 02debug.c -DDEBUG

打印调试信息:
    #ifdef DEBUG
        #define debug(...) printf(__VA_ARGS__)
    #else
        #define debug(...)
    #endif
打印错误信息:
    #define error(...) printf("%s %s:%d %s %m %s %s\n",__FILE__,__func__,__LINE__,__VA_ARGS__,__DATE__,__TIME__)

头文件中应该写什么:
头文件可能会被任意源文件包含,意味着头文件中的内容可能会在多个目标文件中存在,要保证合并时不要冲突
重点:头文件只编写声明语句,不能有定义语句
全局变量声明
函数声明
宏常量
宏函数
typedef 类型重定义
结构、枚举、联合的类型设计声明
头文件的编写规则:
1、为每个.c文件写一份.h文件,.h文件是对它对应的.c文件的说明
2、如果需要用到某个.c文件中的变量、函数、宏时,只需要把该文件的.h文件导入即可
3、.c文件也要导入自己的.h文件,目的是为了让定义与声明保持一致
头文件的相互包含:
假如a.h包含了b.h的内容,而b.h中又包含了a.h的内容,这时就会产生头文件的相互包含,无法编译通过
解决方案:把a.h中需要b.h的内容,和b.h中需要a.h的内容提取出来,额外再写另一个c.h

Makefile:
Makefile是由一系列的编译器指令组成的可执行文件,叫做编译脚本
在终端执行 make 命令就会自动执行Makefile脚本中的编译指令,它可以根据文件的修改时间、和依赖关系来判断哪些文件需要编译,哪些不需要编译
需要一个名字叫做 Makefile 的编译文件
Makefile的编译规则:
1. 如果这个工程没有编译过,那么我们的所有c 文件都要编译并被链接。
2. 如果这个工程的某几个c 文件被修改,那么我们只编译被修改的c 文件,并重新链接目标程序。
3. 如果这个工程的头文件被改变了,那么引用了这几个头文件的c 文件都会重新编译,并链接目标程序。

一个最简单的Makefile脚本格式:
执行总目标:依赖
    编译指令
被依赖的目标1:依赖的文件
    编译指令
被依赖的目标2:依赖的文件
    编译指令

标签:__,char,const,语言,学习,缓冲区,字符串,输入
From: https://www.cnblogs.com/c-learnmore/p/17583543.html

相关文章

  • openGauss学习笔记-21 openGauss 简单数据管理-GROUP BY子句
    openGauss学习笔记-21openGauss简单数据管理-GROUPBY子句GROUPBY语句和SELECT语句一起使用,用来对相同的数据进行分组。您可以对一列或者多列进行分组,但是被分组的列必须存在。21.1语法格式SELECT{*|[column,...]}[FROMfrom_item[,...]][WHEREcondition][......
  • 通过机器学习增强移动广告能力:案例研究
    介绍在数字时代,移动广告主和跨渠道广告活动家越来越需要利用机器学习的力量来创建更有效的营销策略。为了扩大他们的软件优势,一位这样的客户与FissionLabs接洽,希望建立一个先进的、支持机器学习的广告平台。该平台旨在为广告商提供无缝的营销活动管理、实时竞价功能以及以TB级......
  • 【学习笔记】扫描线
    【别急,我也不会,没写完】目录定义:例题(解释):定义:如图:(图片来源:oiwiki)像这样的一条线在图上扫描时,便是扫描线。(呃呃和没说没有任何区别呢)因此可见扫面线往往是求矩形面积并集或周长并集的好工具,当然,也可以运用在二维图中。当然它不止可以从上往下扫,还可以从左往右扫:(当然自己......
  • Python学习4
    Python学习(二)1Python集合1.1集合(Set)集合是无序和无索引的集合。在Python中,集合用花括号编写。1.2访问项目您无法通过引用索引来访问set中的项目,因为set是无序的,项目没有索引。但是您可以使用for循环遍历set项目,或者使用in关键字查询集合中是否存在指定值。......
  • c++学习:封装、继承、多态
    c++是面向对象的编程语言,相对于c具有封装、继承、多态的特点。封装定义:封装就是将对象的属性和行为封装起来,形成一个有机的整体,其载体就是类。类通常对客户隐藏其实现细节,这就是封装的思想,就比如我们使用一个库函数时,我们只需要知道它的作用就可以了,没必要去了解它的内部工......
  • Docker学习路线12:开发者体验
    到目前为止,我们只讨论了使用Docker来部署应用程序。然而,Docker也是一个极好的用于开发应用程序的工具。可以采用一些不同的建议来改善开发体验。在应用程序中使用docker-compose以方便开发。使用绑定挂载将本地代码挂载到容器文件系统中,以避免每次更改都需要重新构建容器映像。......
  • go语言gorm的CRUD
    插入如果表不存在,则插入失败typeStudentstruct{IDint//缺省主键bigintAUTO_INCREMENTNamestring`gorm:"size:48"`//`gorm:"notnull;type:varchar(48);comment:姓名"`Agebyte//byte=>tinyintunsignedBirthday......
  • 基于C语言的P2P软件实现
    完整资料进入【数字空间】查看——搜索"writebug"摘要Peer-to-Peer网络毫无疑问是当今的热点技术主题。Napster和Gnutella的广泛使用证明了peer-to-peer应用的强大潜力。P2P(或者说peer-to-peer)网络是一种基于操作上下文的网络模型,任何一个节点都同时作为客户机和服务器。J......
  • c++学习:程字辈(进程、线程、协程)
    程字辈(进程、线程、协程)介绍C++中的进程、线程、协程之间的联系及区别。(以linux下实现为例)进程概念:进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来......
  • AOP的学习-入门
    切面(Aspect)用来绑定通知(Advice)也就是日志和增强对方法-切入点(Pointcut)开发案例思路: 其中主要的是定义通知类后需要在类中写切入方法和通知方法  其中切入点表达式的格式  基本格式为表示在该类中所有方法, ......