C语言于1969年至1973年间,为了移植与开发UNIX操作系统,由丹尼斯·里奇与肯·汤普逊,以B语言为基础,在贝尔实验室设计、开发出来。
介绍
- C是一种通用的、过程式编程编程语言,支持结构化编程、词法作用域和递归,使用静态类型系统,并且广泛用于系统软件与应用软件的开发
- 操作系统
- 设备驱动等
- C++、Java借鉴C开发
- C++、Java、Python(cpython)等编译器或解释器基于C语言开发
- C语音被称为编程之母
- 1989年,
ANSI(美国国家标准协会)
发布第一个C语言标准 ANSI X3.159-1989(简称C89)
,常称为 ANSI C
优点
环境部署
brew install gcc
开发工具
- CodeBlock
- Visual Studio
- vscode
- C/C++(ms-vscode.cpptools)
- C/C++ Runner(franneck94.c-cpp-runner)
hello world
C语言的入口函数为 main
函数
/*
hello world
*/
#include <stdio.h>
/* 函数定义 */
void say() {
printf("hello world");
}
int main() /* main 函数 */
{
say(); // 函数调用
return 0;
}
说明:
/* */
注释
#
开头,预处理指令,由预处理器处理
main
的 ()
表示函数的参数
{}
表示函数体
printf()
输出到屏幕
return 0;
表示函数的返回值,函数结束时执行
0
返回给操作系统,表示正常结束;非0
表示错误结束
编译
$ gcc helloworld.c -o helloworld
$ ./helloworld
hello world%
基础元素
-
基本数据类型
int
整形
char
字符型
- 字符串:结尾带有
结束字符("\0")
的字符数组
- 字符串中,通过某个字符是否等于
\0
判断是否结束
float
单精度浮点实数型
double
双精度浮点实数型
short
long
unsigned int
unsigned char
-
派生类型
- 数组:
int arr[]; int arr1[5];
int arr[3] = {1, 2, 3};
int arr[] = {1, 2, 3};
- 指针:
int *p; char *c;
-
变量:指定类型内存块的名称
-
32位编译器数据占用字节数
char |
short |
int |
long |
float |
double |
指针 |
1 |
2 |
4 |
4 |
4 |
8 |
4 |
char |
short |
int |
long |
float |
double |
指针 |
1 |
2 |
4 |
8 |
4 |
8 |
8 |
操作符
- 算术运算符:
+
、-
、*
、/
、%
、++
、--
- 比较运算符:
>
、<
、>=
、<=
、!=
- 逻辑运算符:与
&&
、或 ||
、非 !
- 符合运算符:
-=
、+=
、*=
、%=
、&=
、|=
、^=
、~=
函数
/* 函数定义 */
返回值类型 函数名(形参类型1 形参1, 形参类型2 形参2)
{
函数体
return 返回值;
}
/* 函数调用 */
函数名(实参1, 实参2)
流程控制
条件 if else
if (条件表达式1)
程序块1
else if (条件表达式2)
{
程序块2
}
else
程序块3
选择 switch
switch (条件表达式1)
{
case 常量1:
程序块1
break;
case 常量2:
程序块2
break;
default:
程序块3
}
循环 for
for(初始表达式; 条件表达式; 条件处理) {
程序块
}
循环 while
while(表达式) {
程序块
}
// 或
do
程序块
while(表达式);
编译指令
- 条件
#if
、#elif
、#else
、#endif
,作用:预处理器依据条件来判断保留或删除某段源代码
#if 表达式1
[ 组1]
[#elif 表达式2
[ 组2]]
...
[#elif 表达式n
[ 组n ]]
[#else
[ 组n+1 ]]
#endif
#if defined( xxx ) && defined( xxx )
/* ... */
#endif
#ifdef 标识符
#ifndef 标识符
宏
- 宏定义:
#define NAME VALUE
- 作用
- 预处理器将程序中的 NAME 使用对应 VALUE 替换,便于理解,防止出错
- 提取程序中经常出现的参数,便于快速修改
#include <stdio.h>
#if 0
int main()
{
printf("0");
return 0;
}
#else
int main()
{
printf("1");
return 0;
}
#endif
常用库
stdio.h
标准输入输出头文件 stdio.h
printf
输出到屏幕
- 格式:
int printf("格式串", 参数1, 参数2, ...)
- 转义字符
\n
换行符
\t
水平制表符
\v
垂直制表符
\\
反斜杠
\?
问号
\a
响铃
\'
单引号
%%
百分号 %
- 占位符
%c
char 类型
%d
int 类型
%f
float 类型
%lf
double 类型
%s
字符串类型
%10s
宽度 10,右对齐
%-10s
宽度 10,左对齐
sizeof()
变量(对应的类型)占用内存的大小
scanf()
从键盘输入数据,float x; scanf("%s", &x);
math.h
string.h
strlen("xxx")
获取字符串长度
strcyp(x, "str")
指针
指针(pointer)
本质是变量的地址,通过取地址运算符&
获取一个变量的地址,如:&x
指针变量
:存储指针(地址)
的变量
类型 *
是指针类型,用来存储类型变量的地址
解引用运算符 *
用来获取一个指针变量指向的变量
int x = 8, y = 8;
int *p = &x;
*p = 6;
b = *p;
int arr[] = {1, 2, 3};
int *p = arr; /* 等价于 int *p= &(arr[0]) */
char ch, *p, crr[]={'h', 'e', 'l', 'l', 'o'}
p = &ch;
*p = 'x'; // ch is 'x'
p = crr;
*p = 'H'; // crr is {'H', 'e', 'l', 'l', 'o'}
*(p+2) = 'L'; // crr is {'H', 'e', 'L', 'l', 'o'}
char *p, *q, crr[]={'h', 'e', 'l', 'l', 'o'}
p = crr;
*q = crr + 5;
while(p < q) {
printf("%c ", *p);
p++;
}
void swap(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
int main() {
int x = 3, y = 4;
swap(&x, &y);
printf("%d %d\n", x, y);
return 0;
}
- 数组名本质是数组第一个元素的地址,因此数组作为函数变量传递时,本质为指针(地址)
struct
- struct 用来定义自定义数据类型
- 使用
成员访问符号(.)
访问结构体的成员
- 结构体指针
struct 结构体名 *
- 使用
访问运算符(->)
访问结构体指针的成员
/* 定义结构体 */
struct Student
{
char name[10];
int age;
floag score;
};
// 实例化
struct Student stu;
stu.age = 18;
strcpy(stu.name, "xianbin"); // strcpy 将常量复制到 stu.name 中
stu.score = 60;
// 结构体指针
struct Student *sp;
p = &stu;
(*p).age = 19;
strcpy((*p).name, "xiexianbin");
sp->score = 100;
内存管理
malloc()
在内存堆区分配一块内存空间
realloc
重新分配内存,并将旧内存地址中的内容复制到新的内存空间中
free
释放内存
int *p = (int *)malloc(3*sizeof(int));
*p = 1;
*(p+1) = 2;
p[2] = 3;
for(int i=0; i<3; i++)
printf("%d\t", p[i]); // p[]i eq *(p+1)
printf("\n");
// 重新分配内存
p = (int *)realloc(p, 6*sizeof(int));
// 释放内存
free(p);
文件读写
// 打开文件
File *fopen("文件路径", "打开模式");
// 关闭文件
int fclose(FILE *文件指针);
// 返回值大于0,读入的个数;返回值小于等于,则读入失败
int fscanf(FILE *fp, const char *format, ...)
// 返回值大于0,写入的个数;否则失败
int fprintf(FILE *fp, const char *format, ...)
// int 返回读入的字符,失败返回 EOF
int getc(FILE *fp);
// 将字符写入文件,返回写入成功的个数,失败返回 EOF
int putc(int character, FILE *fp);
char * fgets(char *str, int num, FILE *fp);
char * fputs(char *str, FILE *fp);
// 移动文件指针,到指定的位置读或写
int fseek(FILE *stream, long offset, int whench)
// 返回当前文件指针,相对于文件开头的位移量
long filesize = ftell(fp);
- 打开模式
w
只写,创建文件或覆盖已经存在的文件
r
只读,打开存在的文件,若文件不存在,报错
a
append 追加文件,若文件不存在,报错
rb
、wb
、ab
二进制模式
r+
、w+
、a
、等
FILE *fp;
fp = open("./a.txt", "a")
if (fp==0)
{
printf("open file err");
return 1;
}
fclose(fp);
常见错误
- 变量未定义:
warning: 'xxx' is used uninitialized in this function [-Wuninitialized]
- 定义变量未使用:
warning: unused variable 'xxx' [-Wunused-variable]
return
前一行缺少 ;
:error: expected ',' or ';' before 'return'
扩展
GCC(GNU C Compiler)
又称GNU C语言编译器
,是由 GNU 开发的编程语言译器,最早只能处理C语言,后扩展为可处理C++、Fortran、Pascal、Objective -C、Java、Ada、Go以及各类处理器架构上的汇编语言等。因此,又称 GNU 编译器套件(GNU Compiler Collection
)。
- GCC 编译器是 Linux 系统下最常用的
C/C++
编译器,大部分 Linux 默认安装