前言
本篇主要对c语言的学习和回顾 ,将选取较为重要和典型的知识部分进行编写,之后进行对数据结构 ,算法 和结合实际项目中的问题进行分析总结
一、C语言简介
(---------以下部分内容来源于百度学术----------)
C 语言是一种通用的高级语言,最初是由丹尼斯·里奇在贝尔实验室为开发 UNIX 操作系统而设计的。C 语言最开始是于 1972 年在 DEC PDP-11 计算机上被首次实现。
在 1978 年,布莱恩·柯林汉(Brian Kernighan)和丹尼斯·里奇(Dennis Ritchie)制作了 C 的第一个公开可用的描述,现在被称为 K&R 标准。
UNIX 操作系统,C编译器,和几乎所有的 UNIX 应用程序都是用 C 语言编写的。由于各种原因,C 语言现在已经成为一种广泛使用的专业语言。
C 语言是为了编写 UNIX 操作系统而被发明的。
C 语言是以 B 语言为基础的,B 语言大概是在 1970 年被引进的。
C 语言标准是于 1988 年由美国国家标准协会(ANSI,全称 American National Standard Institute)制定的。
截至 1973 年,UNIX 操作系统完全使用 C 语言编写。
目前,C 语言是最广泛使用的系统程序设计语言。
大多数先进的软件都是使用 C 语言实现的。
当今最流行的 Linux 操作系统和 RDBMS(Relational Database Management System:关系数据库管理系统) MySQL 都是使用 C 语言编写的。
二、变量
1.c中变量的定义
变量定义就是告诉编译器在何处创建变量的存储,以及如何创建变量的存储。变量定义指定一个数据类型,并包含了该类型的一个或多个变量的列表
float
单精度浮点值。单精度是这样的格式,1位符号,8位指数,23位小数。
double
双精度浮点值。双精度是1位符号,11位指数,52位小数。
C 语言也允许定义各种其他类型的变量,比如枚举、指针、数组、结构、共用体等等
2.变量的声明
变量声明向编译器保证变量以指定的类型和名称存在,这样编译器在不需要知道变量完整细节的情况下也能继续进一步的编译。变量声明只在编译时有它的意义,在程序连接时编译器需要实际的变量声明。
变量声明的两种情况
- 1、一种是需要建立存储空间的。例如:int a 在声明的时候就已经建立了存储空间。
- 2、另一种是不需要建立存储空间的,通过使用extern关键字声明变量名而不定义它。 例如:extern int a 其中变量 a 可以在别的文件中定义的。
extern int i;// 声明 ,但不是定义
int i; // 声明并却定义
有些情况下 , 可以在通过extern 来在函数内声明 外部变量 ,其中变量在头部就已经声明, 但定义和初始化将在函数内部进行
#include <stdio.h>
// 函数外定义变量 x 和 y
int x;
int y;
int addtwonum()
{
// 函数内声明变量 x 和 y 为外部变量
extern int x;
extern int y;
// 给外部变量(全局变量)x 和 y 赋值
x = 1;
y = 2;
return x+y;
}
int main()
{
int result;
// 调用函数 addtwonum
result = addtwonum();
printf("result 为: %d",result);
return 0;
}
也可以使用extern来在一个源文件中引用另外一个源文件的变量
, 我们只需要在引用文件中将变量加上extern 关键字声明即可
==注意在定义变量是 专业术语 — 左值和右值 ==
- 左值(lvalue):指向内存位置的表达式被称为左值(lvalue)表达式。左值可以出现在赋值号的左边或右边。
- 右值(rvalue):术语右值(rvalue)指的是存储在内存中某些地址的数值。右值是不能对其进行赋值的表达式,也就是说,右值可以出现在赋值号的右边,但不能出现在赋值号的左边。
变量是左值,因此可以出现在赋值号的左边。数值型的字面值是右值,因此不能被赋值,不能出现在赋值号的左边。
枚举(enum)
枚举是 C 语言中的一种基本数据类型,它可以让数据更简洁,更易读。
//使用define来为每个整数定义一个别名:
#define MON 1
#define TUE 2
#define WED 3
#define THU 4
#define FRI 5
#define SAT 6
#define SUN 7
// 如果使用枚举的方法
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};
enum 枚举名 {枚举元素1,枚举元素2,……};
在使用枚举的时候 , 注意枚举类型的转换,不能够直接进行强转
#include <stdio.h>
#include <stdlib.h>
int main()
{
enum day
{
saturday,
sunday,
monday,
tuesday,
wednesday,
thursday,
friday
} workday;
int a = 1;
enum day weekend;
weekend = ( enum day ) a; //类型转换
//weekend = a; //错误
printf("weekend:%d",weekend);
return 0;
}
函数的传值和调用
-
如果函数要使用参数,则必须声明接受参数值的变量。这些变量称为函数的形式参数-------形参
形参就想函数内的其他局部变量, 在进入函数时被创建, 退出时被销毁。 -
调用函数时, 有两种向函数传递参数的方式
- 传值调用
这种方法主要把参数的实际值赋值给函数的实际参数, 在这种情况下, 修改函数内的形式参数不会影响实际参数 。
默认情况下, C语言使用传值调用方法来传递参数, 一般来说, 这意味着函数内的代码,不会改变用于调用函数的实际参数, ----------- 值不变 - 引用调用
通过引用传递的方式, 形参指向地址
- 传值调用
#include <stdio.h>
/* 函数声明 */
void swap(int *x, int *y);
int main ()
{
/* 局部变量定义 */
int a = 100;
int b = 200;
printf("交换前,a 的值: %d\n", a );
printf("交换前,b 的值: %d\n", b );
/* 调用函数来交换值
* &a 表示指向 a 的指针,即变量 a 的地址
* &b 表示指向 b 的指针,即变量 b 的地址
*/
swap(&a, &b);
printf("交换后,a 的值: %d\n", a );
printf("交换后,b 的值: %d\n", b );
return 0;
}
4.指针
我们平时所使用的数组, 数组名其实就是一个指向数组中第一个元素常量指针
例如 double scores[50];
score 是一个指向 &score[0]的指针 。 因此如果存在某个指针变量p 指向 score ,那么使数组名为常量指针也是合法的,
double *p = score;
*(p+4) // 访问score数据的第5个元素
利用指针可以进行动态分配,和实现一些复杂的数据结构或算法, 每个变量都对用一个内存, 可以使用&来提取出变量的地址,在使用指针的时候要根据访问变量的数据类型,来定义对应类型的指针变量 ,
在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。
NULL 指针是一个定义在标准库中的值为零的常量
指针变量只储存着指向变量的地址,切与被指向变量的类型一致
5.指向指针的指针
指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。
一个指向指针的指针变量必须如下声明,即在变量名前放置两个星号
int **var;
实例
#include <stdio.h>
int main ()
{
int V;
int *Pt1;
int **Pt2;
V = 100;
/* 获取 V 的地址 */
Pt1 = &V;
/* 使用运算符 & 获取 Pt1 的地址 */
Pt2 = &Pt1;
/* 使用 pptr 获取值 */
printf("var = %d\n", V );
printf("Pt1 = %p\n", Pt1 );
printf("*Pt1 = %d\n", *Pt1 );
printf("Pt2 = %p\n", Pt2 );
printf("**Pt2 = %d\n", **Pt2);
return 0;
}
5.C语言函数指针和回调函数
- 函数指针是指向函数的指针变量。
通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。
函数指针可以像一般函数一样,用于调用函数、传递参数。
函数指针变量的声明:
声明一个指向同样参数、返回值的函数指针类型
typedef int (*fun_ptr)(int,int);
指针函数最重要的一点就是 - 其声明的时候 ,参数一定要和指向函数的参数保持一致。
#include <stdio.h>
int max(int x, int y) //定义一个将被指向的函数
{
return x > y ? x : y;
}
int main(void)
{
/* p 是函数指针 */
int (* p)(int, int) = & max; // 取址符 &可以省略
int a, b, c, d;
printf("请输入三个数字:");
scanf("%d %d %d", & a, & b, & c);
/* 与直接调用函数等价,d = max(max(a, b), c) */
d = p(p(a, b), c);
printf("最大的数字是: %d\n", d);
return 0;
}
- 回调函数
函数指针作为某个函数的参数
函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的函数。
简单讲:回调函数是由别人的函数执行时调用你实现的函数。
一般情况下,应用程序,会时常通过API调用库里所预先备好的函数,但是有些库函数,却要求应用先传给他一个函数, 好在适合的时候调用,已完成目标任务, 这个被传入的, 后又被调用的函数成为回调函数。
- 结构体内部包含指针
我们知道结构体的成员可以包含其他结构体,也阔以包含指向自己结构类型的指针, 而通常这种指针的应用是为了实现一些更高级的数据结构入链表和树
struct NODE
{
char string[100];
struct NODE *next_node;
};
6.0 指向结构体的指针
可以定义指向结构的指针, 方式与定义指向其他类型变量的指针类似
struct Book *struct_pointer;
struct_pointer = &Book1;
7.0 从函数中返回指针
c语言允许从函数返回指针, 但必须声明一个返回指针的函数
int *Function(){
........
....
..
}
当然前边写记载如何传递指针到函数