2019独角兽企业重金招聘Python工程师标准>>>

一、函数

  • 什么情况下需要定义一个函数?

    • 常用的功能
    • 重复的功能
    • 低效率的代码
  • 一个函数可以没有参数
void  test(void){ //void可以不写//函数体中不用写返回函数(return)
}
  • 一个函数可以没有返回值,如果没有定义,默认是返回int类型
test(int a, int b){ //返回值类型可以不写,如果不写,默认为返回int类型
}
  • 在没有接触指针前,函数中的形参是修改不了实参的值的
  • 函数从源文件自上往下执行编译,所以在调用函数之前,需要声明函数
  • 函数内部定义不能和形参同名的变量
  • 默认情况下,不允许两个同名的函数出现
  • 如果函数有声明,没有定义,编译不会报错,链接会报错,因为链接会检测函数是否存在
  • return函数的作用
    • 退出函数
    • 返回一个具体值给函数调用者
  • 函数不强制要求返回,虽然声明了返回值类型,也无济于事
  • 什么叫做链接?
    • 把项目中所有相关联的”.o”文件和C语言函数库,合并在一起,生成可执行文件,期间会检查可能发生的错误,如果出现错误,就会回到编写代码的步骤,修改相应错误代码后,再执行流程
  • 函数的定义和声明
    • 函数的定义放在”.c”文件中
    • 函数的声明放在”.h”文件中
  • main函数返回值0代表正常退出,返回其他值代表异常退出,系统会记录日志
  • printf()函数其实也有返回值,它返回字符串的字节数,在当前的编译器中,中文占3个字节二、指针
  • 定义和初始化指针
int a = 10; //定义了一个int类型的变量
int *pa  = NULL; //定义了一个int类型的指针
pa = &a; //将int类型变量a的地址赋值给pa指针,或者说pa指针指向了变量a
*pa = 20; //通过指针简介修改变量a的值,*称为取消引用运算符或间接运算符

二、指针

  • 指针只能指向相同类型的变量并且指针只能存储地址
  • 任何指针都占用8个字节的存储空间,当然也受编译器的影响
  • 通过指针就可以利用形参修改实参的值,因为指针指向的是地址
  • 指针字符串
//使用char数组存储字符串,这个叫做字符串变量
char str1[] = “luoguankun”;
//使用指针存储字符串,它指向字符串的首字母
//这个称为字符串常量,如果再声明一个字符串值一样的指针字符串
//那么他们会指向同一 个字符串,而不会创建一个新的
char *str2 = “luoguankun”;
  • %s

    • 上面的输出语句中的%s是字符串输出控制格式符
    • 它从第一个字符开始直到遇到’\0’终止符号结束(不包括)
  • 内存
    • ——就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。里面的变量通常是局部变量、函数参数等
    • ——就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收
    • 自由存储区——就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的
    • 全局/静态存储区——全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区
    • 常量存储区——这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多)
  • \0
    • 只有拥有’\0’终止符,才说明这是一个字符串,字符是没有的
    • \0 的ASCII码值为0,也就是false
  • 指针数组
    • 数组就是地址
int *name[5];
name[1] //取出元素下标为1的元素(指针)
  • 字符串数组(两种方式定义)

    • char *name[10]      //10个字符串
    • char name[2][10]    //二维字符数组,可存放2行字符串,每行有10个字符
  • 指向指针的函数
//定义了一个加法函数
int sum(int a, int b){return a+b;
}//将定义好的指针指向函数
//首先声明一个指针
int (*p)(int,int);     //其中(*p)代表将来指向的函数,(*p)左右分别为返回值类型和形参定义
p = sum; //将指针p指向test函数
p(10,22); //通过指针调用函数,它等于sum(10,22);当然在调用之前别忘了声明函数
  • 可以使用sizeof()运算符计算字符串长度(计算的是字节数)

    • sizeof()的结果类型是size_t类型,它在头文件中用typedef定义为unsigned int类型
    • sizeof()运算符可以用任何类型做参数,甚至函数
  • 也可以使用strlen()函数计算字符串长度
    • strlen()只能用char*做参数,且必须是以’’\0’'结尾的
    • 要想使用需要引入<string.h>头文件
  • 变量类型

    • 全局变量

      • 定义:在函数外面定义的变量叫做全局变量
      • 作用域:从定义变量的那一行开始,到文件结尾
      • 生命周期:当程序启动开始分配存储空间,到程序退出才会被销毁
      • 初始值如果未定义就为0
    • 局部变量
      • 定义:在函数代码块内部定义的变量
      • 作用域:从定义变量的那一行开始到代码块结束
      • 生命周期:从定义变量开始分配存储空间,代码块结束后就会被回收
      • 初始没有确定的值

三、结构体

数组只能存储一组同类型的数据,而结构体可以保存一组不同类型的数据

  • 定义结构体类型

//以下定义没有分配存储空间,仅仅定义类型

struct Person {int age;int sex;char *name;
};
  • 定义结构体变量

struct Person p;
  • 赋值
p.age = 13; //一种方式//另一种方式,初始化的同时进行赋值,同时进行分配存储空间
//结构体的存储空间是最大成员字节数的倍数,称为补齐算法
struct Person p = {13,1,”luoguankun”};p = {13,1,”luoguankun”}; //这是错误的!只能在定义结构体时赋值
  • 输出结构体中定义的变量值
printf(“age=%d,sex=%d,name=%s”,p.age,p.sex,p.name);
  • 另一种定义结构体变量的方式
//定义类型的同时定义变量,甚至可以不写类型名称,称为匿名结构体,它不能被重用
//并且变量名不能重复
struct Student{int age;
}stu;
  • 类型不能重复定义,例如上面的Student不能被定义两次,变量名也一样不能重复
  • 结构体数组
//定义结构体类型
struct Person{int age;double height;char *name;
}stu;//定义结构体数组变量并赋值初始化
struct Person stu[3] =
{{11,12.1,"o"},{12,12.2,"u"},{13,12.3,”l"}};//循环遍历结构体数组,并打印
for (int i = 0; i < sizeof(stu) / sizeof(stu[0]); i++) {printf("age=%d,height=%.1f,name=%s\n",stu[i].age,stu[i].height,stu[i].name);
}//stu[i] = {4,1.22,”dkdk”}; //这是错误的stu[i].age = 4; //这样是正确的
  • 指向结构体的指针
//省略类型定义,如上,下面使用结构体变量并赋值初始化
struct Person stu = {11, 1.73, "罗冠坤"}; //定义了一个指针p并指向结构体变量stu
struct Person *p = &stu;//三种输出方法都可以输出数据,作用相同,其中p->成员名的方式较为新颖
printf("age=%d,height=%.2f,name=%s\n",stu.age,stu.height,stu.name);
printf("age=%d,height=%.2f,name=%s\n",(*p).age,(*p).height,(*p).name);
printf(“age=%d,height=%.2f,name=%s\n",p->age,p->height,p->name);//赋值方法的调用方法相同
  • 嵌套结构体
int main(){struct Date{int year;   //年int month;  //月int day;    //日};struct Student{int no; //学号//嵌套两个Date来分别表示生日和入学日期struct Date birthday;   //生日struct Date SchoolDay;  //入学日期};struct Student stu ={1,{1989,10,24},{2009, 9, 1}};//间接取值,嵌套访问printf("学号为:%d\n生日为:%d年%d月%d日\n入学日期为:%d年%d月%d日\n",stu.no,stu.birthday.year,stu.birthday.month,stu.birthday.day,stu.SchoolDay.year,stu.SchoolDay.month,stu.SchoolDay.day);return 0;}

四、预处理指令

  • 所有预处理指令都是以#开头
  • 不带参数的宏定义
//宏名  值;
#define//宏的变量名全部是大写,结尾不需要写分号
#define  COUNT  6//还可以取消宏的定义
#undef COUNT
  • 编译器的作用是将原代码文件中的代码翻译成机器可执行的代码,也就是0和1,而预处理指令会在编译器翻译代码之前执行
  • 带参数的宏定义
/*一定要加括号,否则会出现意想不到的结果比如像下面这样调用sum(10,10) * sum(10,10);相当于下面:10+10*10+10   这样替换过后改变了运算顺序,也就改变了预期的运算结果所以一定要把所有变量都加上括号再比如平方的例子一定要像下面这样写,每个形参都要加上括号#define Square(a)((a)*(a))*/#define sum(v1,v2)((v1)+(v2))int main(void){int result = sum(11,10);printf("result=%d\n",result); //输出了21return 0;
}
  • 宏定义只是单纯的把左边的定义(比如:sum(v1,v2))替换成右边的(比如:(v1)+(v2)),不做任何运算
  • 在常见的比较简单的函数可以使用宏定义,这样比函数效率要高
  • 条件编译
#define A 10int main(){//条件编译判断如果用到常量值,比如下面的A
//则必须得是通过宏定义的,因为在编译前已经进行了判断
//条件的括号可以省略    #if (A == 10)printf("a = 10\n");#elif (A == 5)printf("a = 5\n");#elseprintf("a is other number\n");#endif //一定要有#endif结尾return 0;}
  • 防止文件多次被包含

当进行多文件开发时,某些函数功能,需要在.h文件中进行声明,还要将.h文件包含到某个文件中,当代码量过大时,有可能发生多次包含,这虽然不会产生错误,但是会影响性能,所以在头文件中可以利用条件编译,防止多次包含头文件,例如像下面这样定义头文件:

/*
解释下面的写法的逻辑:
如果没有定义宏 ABC
那么就定义一个宏ABC
并且声明sum()函数
如果第二次被包含时,同样会进行判断
此时判断的条件不成立,因为第一次被包含时已经创建了宏变量ABC
所以这样一来,避免了重复包含同一个头文件
ABC宏名称不能和别的头文件中的冲突!所以一般使用当前.h头文件名称命名
*/// #ifndef等同于#if !define,对应的有#ifdef 等同于 #if define
#ifndef ABC
// ABC一般写成当前头文件的名称,后面的值随便写#define ABC 11int sum(int,int);
#endif
  • typedef

    • 定义类型的别名(一般是全局变量,方便被使用),使用typedef以后,会提高开发效率
    • 应用于5个场合
  1. 基本数据类型
  2. 指针
  3. 枚举
  4. 结构体
  5. 指向函数的指针
  • 应用于基本数据类型
//需要分号
typedef int MyInt;int main(){//声明别名后,可以这样定义int类型变量MyInt i = 10;
}
  • 应用于指针
//给指针类型起了一个别名String
type char* String;int main(){String = “luoguankun”;
}
  • 应用于结构体
//定义了一个结构体类型Student
struct Student {int age;
};//给结构体Student起了个别名叫做Mystu
typedef struct Student MyStu;//或者像下面这样,在定义结构体类型的时候直接起别名,这样更加精简
typedef struct Student {int age;
}MyStu;//如果像上面这样给结构体起了别名,定义结构体变量就变成了下面这样:
MyStu s1;
MyStu s2;
MyStu s3;//还有一种是没有类型名的结构体
//下面的结构体不能使用原本的方式创建结构体变量
//只能通过下面的方式创建结构体变量,无法用struct Student stu = {10};这种方式创建结构体变量,
//而前面几种两种创建结构体变量的方式都可以
//而这个只能像下面这样创建:
//MyStu stu;
typedef struct {int age;
}MyStu;
  • 应用于枚举类型
//以下是没有使用typedef定义别名时的枚举使用
enum Sex {Man, Woman};
enum Sex s = Man;//以下是使用typedef定义别名后的使用方法
typedef  enum  Sex MySex;
MySex s = man;//还可以在定义枚举类型的同时定义别名(推荐这样定义)
typedef  enum Sex {Man, Woman} MySex;
MySex s1 = man;
  • 应用与指向函数的指针
//定义一个函数
int sum(int a, int b){return a+b;
}
//指向上面函数的指针声明和调用
int (*p)(int, int) = sum;
int result = p(10,20);//使用typedef为指向函数的指针定义别名
typedef int (*MyPoint)(int, int);MyPoint p = sum;
int result = p(20,20);
  • 简化指向结构体的指针
//简化前
struct Person{int age;
}; struct Person p = {20};
struct Person *p2 = &p;
printf("age = %d\n”, p2->age);//简化后
typedef struct Person{int age;
} *PersonPoint;struct Person p = {20};
PersonPoint p2 = &p;
printf("age = %d\n", p2->age);

五、static和extern对函数的作用

  • 这两个关键字分别代表内部和外部函数

    • static —— 内部函数,只能被本文件访问,其他文件不能访问,但可以通过外部函数间接访问
    • extern —— 外部函数(默认)
  • 在多文件开发的情况下,不同文件中的外部函数不可以重名,内部函数可以同名,但在同一个文件中内外部函数都不能重名
  • 定义完整的外部函数需要在函数前加上extern关键字,也可以省略,因为它是默认的
  • 定义内部函数需要在函数前面加上static关键字
  • 虽然被static关键字修饰的函数不能被外部文件直接调用,但可以间接调用,在外部函数中调用内部函数(条件是要被间接调用的内部函数和外部函数在同一个文件),并且必须在外部函数的上面被声明

六、static和extern对变量的作用

  • 全局变量分为两种:

    • 外部全局变量——默认,类型关键字前面无需加任何修饰符
    • 内部全局变量——被static修饰符修饰
  • 默认情况下,所有的全局变量都是外部变量,不同文件中的同名变量,都代表同一个变量
  • 内部变量:只能被本文件访问,不能被别的文件访问,不同文件同名的内部变量,互不影响
  • static对变量的作用:定义一个内部变量
  • extern对变量的作用:声明一个外部变量
  • static对函数的作用:定义和声明一个内部函数
  • extern对函数的作用:定义和声明一个外部函数(可以省略)

六、static对局部变量的作用

  • 延长局部变量的生命周期直到程序结束
  • 期间并没有改变局部变量的作用域
  • 使用场合:
    • 某个变量的值固定不变,而被调用的次数又非常多,就应在变量前加上static修饰符

转载于:https://my.oschina.net/luoguankun/blog/219392

C语言自学《八》---- C语言知识总结相关推荐

  1. Go语言自学系列 | go语言数字类型

    视频来源:B站<golang入门到项目实战 [2021最新Go语言教程,没有废话,纯干货!持续更新中...]> 一边学习一边整理老师的课程内容及试验笔记,并与大家分享,侵权即删,谢谢支持! ...

  2. Go语言自学系列 | 汇总

    视频来源:B站<golang入门到项目实战 [2021最新Go语言教程,没有废话,纯干货!持续更新中...]> 一边学习一边整理老师的课程内容及试验笔记,并与大家分享,请移步至知乎网站,谢 ...

  3. 自学golang【第一章:go语言基础知识】为什么要学习go语言?go语言与c语言的关系?go语言创始人?go语言的特性有哪些?go语言适合做什么?国内外有哪些企业或项目使用go语言?

    事先声明:本文部分内容参考了尹成的笔记,如果侵权请联系删除. 我是一名自学go语言的初学者,从今天开始我将会坚持更新go语言的相关知识,从入门到精通,如果大家有什么需要可以加我QQ:239479969 ...

  4. C语言自学之路七(函数(重点)详解)

    本文所结合图书及视频 <C语言程序设计(第四版)谭浩强.pdf> <C语言入门到精通-鹏哥带你C语言从入门到精通> <郝斌老师的C语言自学视频> 这些在B站上都能找 ...

  5. c语言基本字符集ppt,C语言的字符集和保留字知识讲稿.ppt

    C语言的字符集和保留字知识讲稿.ppt 第一章 概述 重点: C语言的字符集和保留字: C语言词类和语句的分类: C程序的基本结构. 程序--是对解决某个问题的方法的描述: 对计算机来说:程序是用某种 ...

  6. 自学php多久可以工作_PHP语言自学要多久才能工作

    这里整理了PHP语言自学要多久才能工作,想要了解PHP语言自学要多久才能工作的同学,可以查看以下PHP语言自学要多久才能工作详细内容. 很多想要学习PHP语言的人经常咨询,PHP难不难学,PHP语言自 ...

  7. 【自学】C语言程序设计

    [自学]C语言程序设计--前言 前言 **大纲** 程序设计与C语言 算法-程序的灵魂 最简单的C程序设计--顺序程序设计 选择结构程序设计 循环结构程序设计 利用数组批量处理数据 用函数实现模块化程 ...

  8. 2022年最新C语言教程入门,C语言自学教程(最全整理)

    一.c语言教程入门 C语言一经出现就以其功能丰富.表达能力强.灵活方便.应用面广等特点迅速在全世界普及和推广.C语言不但执行效率高而且可移植性好,可以用来开发应用软件.驱动.操作系统等.C语言也是其它 ...

  9. 【经验分享】转行如何自学C/C++语言并且找到工作,分享自己心得

    做C/C++语言开发多年,给大家详细分析一下这个问题 首先告诉你的是,应届生零基础开始学习C/C++语言肯定难,C/C++语言的专业程度本身就不简单,学习这事本来就是一件非常煎熬的事情,人都不愿意学习 ...

  10. C语言结构联合位字段知识体系总结大学霸IT达人

    C语言结构联合位字段知识体系总结大学霸IT达人 C语言的基础类型中只能去定义单一类型的变量用于指代数据,但在现实生活中我们常常要处理的数据却会包含多种类型的数据. 例如,公司员工的信息管理,每个员工的 ...

最新文章

  1. Pycharm的运行和简单调试
  2. 交易性金融资产账务处理问题及改进
  3. 为什么不能在SQL拼接模糊匹配符号
  4. 汉恩互联「绘动画室」,触摸背景墙
  5. 《大西洋月刊》:在线能影响中国高等教育吗?
  6. 你可能没听过的 Java 8 中的 10 个特性
  7. python语法简洁清晰特色之一是强制用什么作为语句缩进_Python解决矩阵问题
  8. 上层应用开发是否真的没有底层开发有前途?
  9. 汇编语言中 编译 连接 构建时的一些错误以及错误的修正方法(不断积累中...)
  10. 常用网页设计html特殊符号转义字符编码查询对照表
  11. ClientHeight
  12. AltiumDesigner16安装教程
  13. GPU共享内存:pycuda使用教程
  14. uniapp 实现抽奖幸运大转盘功能
  15. python修改分辨率和图片像素
  16. 三月的雨季给我带来了希望
  17. IP5306是一款2.1A 充电 2.4 A 放电高集成度移动电源 SOC
  18. 测试人员面试需要掌握的内容
  19. 学习笔记:Maxent的示例运行及部分结果解释
  20. App Store Connect显示app已经上架(可供销售),但在App Store中没有实时更新

热门文章

  1. 用摩斯电码通关《黑暗之魂3》!up主自制奇葩手柄,连育碧都找上门合作
  2. 魔法一样隔空在屏幕写字,捏起手指就能实现!在线可玩
  3. 告别学术论文恐慌!休斯顿大学教授的这个建议,让学术写作更简单
  4. 高通CVPR神研究:视频处理计算量降低78%,教卷积层自己“挑像素”,卡成PPT的视频纵享丝滑...
  5. 号称用GPT-3开发的游戏,却活生生玩出了人性黑暗面
  6. 百度景鲲:疫情居家让智能音箱经受了检验,下一步「破圈」
  7. 北大图灵班本科生带来动画CG福音,「最懂骨骼的卷积网络」,无需配对样本实现动作迁移 | SIGGRAPH...
  8. V-rep学习笔记:机器人路径规划1
  9. 改变,从跨出第一步開始——记海大ITAEM团队首次IT讲座掠影
  10. [物理学与PDEs]第2章习题参考解答