A: c语言是一种底层语言
B: c 语言是一种小型语言
C: c 语言一种包容性语言,c语言假设用户知道自己做什么,
所以她提供了更为广阔的自由度。
优点:
高效
可移植性,c语言编译器规模小,容易编写。
功能强大
灵活
标准库
与UNIX 系统结合紧密
缺点:
出错率高
难理解
难以修改
Gcc( GNU Compiler Collection)
基本用法: gcc [options] [filenames]
-c 只编译,生产.o 为后缀的目标文件,通常用于编译
不包含主程序的子程序文件。
-o output_filename 确定输出文件的名称为
-g 产生符号调试工具gdb 所必要的符号资讯
-O 大写哦 对程序进行优化编译
-O2 比-o 更好的优化编译
-std 例如: -std= c89 或者 -std=c99
概念:
类型:每个变量都必须声明她的类型。C可分为基本数据类型和复合数据类型
声明: 任何变量在使用之前必须进行声明。如: 数据类型 变量名称
初始化:
1. 自动变量未初始化的时候访问,其数值是一个随机数值。
例如:
#include <stdio.h>
Int main()
{
Int day;
Printf(“day = %d\n”,day);
Return 0;
}
标示符: 在编写程序的时候,需要对变量, 函数,宏,以及其他实体进行命名,这些名称成为:标示符。
标示符有五条命名规则:
1. 以字母,下划线开头;
2. 可以包含字母,下划线,数字
3. 大小写敏感
4. 不能和关键字冲突
关键字:
特性:
有特殊含义的一串字符
全部小写
标准库中函数名全部小写
格式化输入/输出
Printf( 格式字符串, 表达式1,表达式2,。。。。) //可变长参数
格式字符串可分为两个部分: 普通字符和 转换说明
转换说明包含以下几部分:
完整格式: % - 0 m.n l或者h 格式字符
1. % 占位符 不能省略
2. - 左对齐,省略 右对齐
3. 0 代表空位填0 省略代表空位不填
4. m 域宽 n 精度
5. l 整数long, 浮点数 double ; h为 short;
6. i /d 输出十进制整数
O 无符号的八进制整数
X 十六进制
u 无符号的十进制
c 输出一个字符
s 输出一个字符串
f 输出一个浮点数
e 以指数的形式输出浮点数
g 在f和e格式之间选择一个较短格式输出
P 输出一个地址
2 %i%d
在printf里面没有区别
在scanf 有区别
%d 只匹配十进制
%i 八进制 十进制, 十六进制
3 如何输出%
%%
绝大数情况下,scanf 只包含转换说明。
Scanf(格式字符串,地址列表);
例如: scanf(“%f%f%f”, &s1, &s2, &s3);
知识点级别:
Char 字符型
Sizeof 是c语言的一个关键字,不是函数。
Sizeof(变量的名字) 或者sizeof (类型)
整数在内存中的存储? b*****b 【准确记忆】
整型在内存中的存储是按照补码形式存储的。整数的补码与源码相同,
负数的补码就是其绝对值的二进制形式按位取反,然后整个数值加 1.
进制转换 【理解描述】
Sizeof 返回一个对象或者类型所占的内存字节数
Sizeof 三种语法方式 b*****b 【准确记忆】
1. Sizeof(类型)
2. Sizeof(变量名)
3. Sizeof(表达式)
Int i=5;
Sizeof(i=10);
算符运算符
1. / 0不能做除数,两个整数相除,取结果的整数部分。
2. % 要求操作数都为整数,如果其中一个不是整数,编译将无法通过。
赋值运算符
Int i,j;
复合赋值 += -= *= /= %=
自增、自减
比较运算符
==
推荐写法: if(15 == data)
逻辑运算符的
短路特性 b*****b【准确描述】
&& || ?:
例子:
#include <stdio.h>
int main()
{
int i=0, j=0;
if(++i || ++j);
if(--i && ++j);
printf("i = %d,j = %d\n",i,j);
return 0;
}
位运算符
按位取反 ~3
按位与 &
用途: b***b 【记忆描述】
经常用来屏蔽某些二进制位(置0)。也可以知道某个二进制位是1还是0。
按位或 |
用途: b***b【记忆描述】
经常用来将某些二进制位 (置 1)。也可以知道某个二进制位是1还是0。
按位异或 ^
运算规则: b*****b 【准确记忆】
对应的二进制位上的数字相同则为0,否则为1。
例子: 判断某个整数二进制格式倒数第三位是 0还是1?
If(data &4) ==4) 倒数第三位1
左移
规则: b*****b 【准确记忆】
左移的时候右边的空位补零
右移
规则: b*****b 【准确记忆】
右移的时候左边补上符号位。
取地址运算
条件运算符
表达式1?表达式2:表达式 3
结构 b*****b【准确记忆写出】
Switch(控制表达式)
{
Case 常量表达式1 :语句1;
Case 常量表达式2 : 语句2;break;
....
Default: .....
}
注意:
控制表达式:计算结果是整型
常量表达式:不能包含变量或者函数调用,最终结果必须是整数。
例如: n+10 不是常量表达式(除非n是表示常量的宏),
每个分支中可以包含多条语句,可以不使用{}
For(表达式1; 表达式2;表达式3)
{
语句;
}
【准确画图】
注意:可以这样写 for(;;){....}
For(i=0;i<10;i++){...}
C99 第一个表达式可以为声明例如:
For(int i=0; i<10; i++){....}
For(i=0,j=0;i<10; printf(),i++,j++){....}
For循环可以嵌套
1. While(1)语句
2. For(;;) 语句
空语句 ;
缓冲区
输入:
键盘->键盘缓冲区-> 输入缓冲区-->程序
#include<stdio.h>
int main()
{
int data_1 = 0, data_2 = 0;
printf("请输入两个整数:");
scanf("%d",&data_1);
scanf("%d",&data_2);
printf("您输入的两个整数是:%d %d\n",data_1,data_2);
return 0;
}
Scanf 失败的原因: 类型不匹配
改成如下:
#include<stdio.h>
int main()
{
int data_1 = 0, data_2 = 0;
printf("请输入两个整数:");
if(scanf("%d",&data_1) == 0)
{
scanf("%*[^\n]");
scanf("%*c");
}
if(scanf("%d",&data_2) == 0)
{
scanf("%*[^\n]"); //读走\n之前的所有字符
scanf("%*c");//读走\n
}
printf("您输入的两个整数是:%d %d\n",data_1,data_2);
return 0;
}
程序-》输出缓冲区-》屏幕
程序的输出可以到达屏幕的条件: b*****b 【描述记忆】
1, \n
2. 程序结束
3. 输出缓冲区满(4kb)
4. 人工刷新(fflush)
例子:
#include <stdio.h>
int main()
{
printf("welcome!");
while(1);
}
结果:没有输出
#include <stdio.h>
int main()
{
printf("welcome!");
fflush(stdout); //新增加的人工刷新
while(1);
}
Scanf(“%s”,&name);
Scanf 遇到空白字符结束
Gets(name)
从输入设备读取一行字符回来,放到name中
危险:gets 不会考虑name的大小,可能导致name的溢出。
Fgets(name,20,stdin);
Fgets会在整个字符串的后面添加\n
例子:
#include <stdio.h>
Int main()
{
Char name[20];
Pritnf(“请输入您的姓名:”);
Scanf(“%s”,name);
Printf(“您输入的姓名是:%s\n”,name);
Return 0;
}
操作字符串的库函数
Strcpy
Strcat
Strncpy
Strncat
Strlen:
strcmp:
一维数组初始化
Int a[5] = {1,2,3} ; //【可描述】如果初始化里面常量表达式个数小于数组元素的个数,剩余的元素初始化为零。
指定初始化
Int a[30] = { [19] = 54, [9]=> 14, [29] = 45 };
Sizeof(数组)
#include <stdio.h>
int main()
{
int a[10];
printf("sizeof(a[0]) = %d\n",sizeof(a[0]));
printf("sizeof(a) = %d\n",sizeof(a));
char c[10];
printf("sizeof(c[0]) = %d\n",sizeof(c[0]));
printf("sizeof(c) = %d\n",sizeof(c));
return 0;
}
宏带参数的宏:
#define sz(a) sizeof(a)/sizeof(a[0])
Int n;
Scanf(“%d”, &n);
Int a[n]; //c99变长数组
函数的返回值
: 函数的返回值必须和return 返回值的类型一致
2. 如果函数没有返回值 指定为void
3. C语言的返回值类型可以省略默认为 int
4.
隐式声明: 如果函数在使用志气没有进行声明,编译器会创建一个隐式声明,返回值类型为int
值传递: c语言中实际参数和形式参数之间采用值传递的方式来传递数据。
#include <stdio.h>
void swap(int a,int b){
int t=a;
a=b;
b=t;
printf("swap:交换中:a = %d b=%d\n",a,b);
}
int main()
{
int x=5,y=7;
printf("main:交换之前:x= %d y= %d\n",x,y);
swap(x,y);
printf("main:交换之后:x= %d y= %d\n",x,y);
return 0;
}
在函数中测试一个参数数组的长度:
#include <stdio.h>
void len(int a[]){
printf("数组总的字节:%d\n",sizeof(a));
printf("传入的数组的长度:%d\n",sizeof(a)/sizeof(a[0])
);
}
int main()
{
int a[20];
len(a);
return 0;
}
什么时候使用const来修饰形参【描述记忆】
如果形参传递的是地址,又不希望在被调用函数更改地址上的内容 这个时候可以使用const 修饰形参。
例如:
Int test(const int r[],int len)
{
r[len-1] = 100;
}
变量的类别
//系统头文件
#include...
//宏定义
#define....
//全局变量
Int data = 1;
//自定义函数的声明
Int main() //主函数
{
//局部变量 local
Int data=2;
For() //if switch while
{
//块变量
Int data = 3;
}
}
//自定义函数
。。。。。
2.1 程序段
: 代码段 存放程序代码的一段区域, 程序段是只读的。
2.2 数据段
:存放已经初始化的全局变量。
2.3 bss段
:通常用来存放程序中未初始化的全局变量和静态变量的一块内存区域
2.4 堆
堆: 保存进程中被动态分配的内存
申请: malloc remalloc(new) OC(alloc new init)
释放: free delete OC(release)
2.5 栈
栈: 存储了程序中临时创建的局部变量。
我们把在函数体中定义的变量叫做这个函数的局部变量。
Int main()
{
Int a,b,c,d........//局部变量
}
Int test()
{
Int a; //局部变量
}
局部变量的特点;
1 生命周期: 从定义这个局部变量的地方开始,到函数的结束。
2. 作用域(访问范围):在定义这个局部变量的函数内(定义这个变量的以下语句);
Static 修饰的局部变量:
特点 【描述记忆】
1 生命周期: 整个程序
2 作用域: 和普通变量一样。
3. 值: 数值就是上一次函数调用结束之后的数值。
例子:
#include <stdio.h>
int test(){
static int i=0;
i++;
printf("i = %d\n",i);
return 0;
}
int main()
{
int i=0; //这里的i和test里面的i不一样
for(;i<6;i++)
{
test();
}
return 0;
}
上个例子中去掉static后的效果:
:定义在整个程序中的变量 称为全局变量
1. 生命周期 :整个程序的生命周期之内
2. 作用域(访问范围):整个程序的范围内都可以访问
3. 值:没有初始化的全局变量的数值是0.
:定义在语句块里面的变量叫做块变量。
程序块(语句块): 使用{}括起来的一组语句。
块变量的特性:
1. 生命周期: 定义变量的地方开始,程序块结束的地方消失
2. 作用域(访问范围):程序块内
For(......)
{
Int i = 0; //块变量
}
If(......)
{
Int temp = i ; // 块变量
}
例子:
#include <stdio.h>
int data = 1;
int main()
{
printf("data = %d\n",data);
int data = 2; //局部变量
printf("data = %d\n",data);
if(1)
{
int data = 3; //块变量
printf("data = %d\n",data);
}
return 0;
}
关键字修饰变量
Auto static register
访问范围: 只能在本文件访问。
即使在其他文件中使用extern声明也不能使用
访问范围:
这个函数只能在本文件中使用
普通局部变量(static 除外)都是 auto ,auto 一般省略。
Auto int i;
:告诉编译器这个变量会被频繁的使用,请保存到寄存器中。
使用限制【描述记忆】
1. 必须能被cpu的寄存器接受(32位= 4个字节)
2. 不能对寄存器变量取地址 &
注意:【描述记忆】
不要返回自动变量的地址。因为自动变量在函数结束之后所使用的内存会被释放。
指针作为函数的参数
字符串
例子:
#include <stdio.h>
int main()
{
char str[5] = "abcde";
printf("str = %s\n",str);
char str1[6] = "abcde";
printf("str1 = %s\n",str1);
char *q = "abcde";
printf("*q = %s\n",q);
return 0;
}
字符串的三种表达方式的区别
1.字面值 。 存在于全局区,不可改变。在内存中只有一个。
2. Char 数组 存在于内存中函数栈,数值可以改变
Char str[] = “abcde”;
//赋值的时候
Str = “abcde”;
3.Char * 既可以指向字面值,也可以指向char 数组里面的元素。
#include <xxx.h>
#include “xxx.h”
区别:
<>到系统指定的路径寻找 一般是: /usr/include
“” 优先从当前目录开始,一般适用于自定义头文件。
1 简单的宏
2. 带参数的宏
//使用宏 判断两个整数中最大的那个
#define MAX(x,y) (x)>(y)?(x):(y)
注意:
参数不能是多次计算之后的数值
MAX(i++,j++) //这是错误的
应该在每个参数的外面加上()
在整个表达式的外面加上()
例子:
#include <stdio.h>
#define MUL(x,y) x*y
int main()
{
printf("结果:%d\n",MUL(3,5));
printf("结果:%d\n",MUL(1+2,2+3));
return 0;
}
8不对呀!
#define MUL(x,y) (x)*(y)
改成上面这样就对了
Printf(“结果:%d\n”,30/MUL(3,5));
应该是 2结果是50;
还要改,改成下面:
#define MUL(x,y) ((x)*(y))
1. #
2. ## 将两个标识符粘贴在一起形成一个标识符
#define MAX(type) type max_##type()
MAX(float) 对应如下:
Float max_float()
1 __LINE__
2 __FILE__
3 __DATE__
4 __TIME__
5 __STDC__ //判断编译器是否符合c 标准 返回0或者 1
条件编译就是根据预处理器的执行结果 来包含或者排除某一段程序。
#if #endif
Defined : 判断一个宏 (有没有定义过这个宏)
#define Debug
#ifdefined Debug
....
#endif
3 #ifdef // 等价于 #if defined
4 #else
#if ...
代码
#elif ...
代码
#else
代码
#endif
【描述记忆】
1, 编写多种硬件环境或者多操作系统上运行的可移植程序。
2,编写用于不同编译器的程序。
#if __STDC__
函数
#else
函数
#endif
3. 产品的调试与发布
4. 为宏提供定义
1 首先对每一个源文件只编译不连接
gcc -c .....
生成 xx.o 文件
2 连接成为一个可执行程序
gcc *.o
自定义的头文件
1.共享宏定义
2.全局变量的声明
例子:
解决方法: 把test.c中的 添加一行 extern int speed;
3. 类型定义共享
【描述记忆】
正确的自定义头文件的编写。
例如:
Test.h
#ifndef TEST_H
#define TEST_H
#include <stdio.h>
#define DISTANCE 1270
#define OIL 13
#endif
描述: makefile 由很多规则组成,一条规则可以分为:
目标文件:依赖文件
命令 (生成目标文件所执行的指令,可以是多条)
给结构起别名?
typedef struct
{
成员列表
} 别名;
使用结构指针作为函数的参数和返回值的时候,可以使程序的效率提高!
结果替的对齐 与补齐?
结构体位段
位段/位域
struct s{
Int i:3; //指定i在内存中占用3个二进制位。
Int b:1;
.....
}
例子:
#include <stdio.h>
//结构体类型的声明
struct test
{
char c1:1;
char c2:2;
char c3:3;
};
int main()
{
printf("sizeof(struct test) = %d\n",sizeof(struct test));
return 0;
}
1, 可以有多个不同类型的成员的组成
2,通过成员的名字访问成员
3,所有成员公用起始地址相同的一段内存
#include <stdio.h>
union
{
int i;
double d;
} test;
int main()
{
printf("sizeof(union test) = %d\n",sizeof(test));
return 0;
}
大端、小端 【准确记忆】
大端: 低字节存储高位数据
小端: 低字节存储低位数据
例子:判断计算机是小端还是大端
#include <stdio.h>
int main()
{
union
{
int i;
char c;
}u;
u.i = 1;
printf("当前计算机:%s\n",u.c == 1? "小端" : "大端");
return 0;
}
规则: enum 枚举名{枚举常量}; //枚举常量之间使用逗号分隔
#include <stdio.h>
int main()
{
enum color {RED,BLUE,GREEN};
//本质上枚举常量就是整数
enum color c;
c = 0; //仅限c语言中
c = BLUE;
printf("RED=%d BLUE=%d GREEN=%d\n",RED,BLUE,GREEN);
return 0;
}
自动变量 :内存都是操作系统维护的。
堆:自己申请 自己释放
栈: 自动分配 自动释放
Malloc -- 分配内存块,不会对分配的内存进行初始化
Calloc -- 分配内存块,对内存进行清零
Realloc -- 调整先前已经分配的内存块的大小
malloc :
Void * malloc(size_t size)
Malloc 分配size字节的内存,返回指向这块内存的指针
#include <stdio.h>
#include <stdlib.h>
int main()
{
int n = 0, i=0;
printf("请输入数组的大小:");
scanf("%d",&n);
int *q = (int *)malloc(n*sizeof(int));
if(q == NULL)
{
//分配失败
printf("error:分配失败\n");
return 0;
}
for(;i<n;i++)
{
q[i] = i+1;
}
for(i=0; i<n; i++)
{
printf("%d ",q[i]);
}
printf("\n");
free(q); //释放动态内存
q = NULL; //置为空指针
return 0;
}
字符串的malloc分配
Char *q = (char *)malloc(n+1);
Struct employee *e = (struct employee *)malloc(sizeof(struct employee));
Void * calloc(size_t nmemb, size_t size);
Calloc 为nmemb个 元素分配内存,每一个元素都是size 个字节大小,自动清零
realloc
:可以根据需求动态的 调整已经分配好的内存。
参数几种情况:
1.内存扩张,realloc 不会初始化扩张的内存
2.失败了,返回空指针,不会影响原来块中的数据
3. 第一个参数 NULL, 相当于 malloc
4.第二个参数0,释放原来的内存块
指针数组
例子:
文件指针: 就是指向FILE结构体的指针。
FILE * fp; //fp就是一个文件指针
文件的操作
fopen: 打开一个文件
fclose: 关闭一个文件
Int fputs() 将一个字符写到文件中
fgetc(); //从文件中读一个字符出来
#include <stdio.h>
int main(int argc ,const char *argv[])
{
FILE *fp = NULL;
if(argc<2 || argc>2)
{
printf("命令的格式不对\n");
printf("Useage:command filename\n");
return 0;
}
if((fp = fopen(argv[1],"r")) == NULL)
{
printf("文件打开失败:%m\n");
return 0;
}
char c;
while(1)
{
c = fgetc(fp);
if(c==EOF)
break;
else
printf("%c",c);
}
fclose(fp);
return 0;
}
/*文件复制*/
#include <stdio.h>
int main(int argc ,const char *argv[])
{
if(argc !=3)
{
printf("格式不对\n");
return 0;
}
FILE *fp1 = NULL;
FILE *fp2 = NULL;
if((fp1 = fopen(argv[1],"r")) == NULL)
{
printf("打开%s失败\n",argv[1]);
return 0;
}
printf("成功打开%s文件\n",argv[1]);
if((fp2 = fopen(argv[2],"w")) == NULL)
{
printf("打开%s失败\n",argv[2]);
fclose(fp1);
return 0;
}
printf("成功打开%s文件\n",argv[2]);
char c;
while(1)
{
c = fgetc(fp1);
if(c== EOF)break;
else
fputc( c,fp2);
}
fclose(fp1);
fclose(fp2);
return 0;
}
Size_t fread(buffer,size,count,fp)
Size_t fwrite(buffer,size,count,fp)
/*文件复制*/
#include <stdio.h>
int main(int argc ,const char *argv[])
{
int i=15, j=63;
FILE * fp = NULL;
if((fp = fopen("c.txt","w")) == NULL)
{
printf("fail to open the file:%m\n");
return 0;
}
printf("success to open the file\n");
fwrite(&i,sizeof(i),1,fp);
fwrite(&j,sizeof(i),1,fp);
fclose(fp);
return 0;
}
使用fread读出来
/*文件复制*/
#include <stdio.h>
int main(int argc ,const char *argv[])
{
int i = 0,j = 0;
FILE *fp = NULL;
if((fp = fopen("c.txt","r")) == NULL)
{
printf("fail to open the file:%m\n");
return 0;
}
printf("success to open the file\n");
if(fread(&i,sizeof(i),1,fp)!=1)
{
printf("读取失败\n");
}
if(fread(&j,sizeof(j),1,fp)!=1)
{
printf("读取失败\n");
}
printf("i = %d j=%d\n",i,j);
fclose(fp);
return 0;
}
Rewind 函数使位置指针回到文件的开头。
Fseek 函数
Int fseek (FILE *stream,long offset, int whence)
Stream: 文件指针
Offset: 位移量
Whence: 起始点
文件开头 0 SEEK_SET
当前位置 1 SEEK_CUR
文件末尾 2 SEEK_END
#include <stdio.h>
typedef struct
{
int ID;
char name[30];
float salary;
} employee;
int main(int argc ,const char *argv[])
{
employee e[3] = {{1, "赵志",500},{2,"月月",500.5},{3,"阿龙",600}};
FILE *fp = NULL;
if((fp = fopen("d.txt","w+")) ==NULL)
{
printf("fail to open the file:%m\n");
return 0;
}
printf("success to open the file\n");
int count = 0;
if((count = fwrite(e,sizeof(employee),3,fp))<3)
{
printf("write error:%m\n");
}
fseek(fp,-3*sizeof(employee),SEEK_CUR); //rewind
employee temp;
int i = 0;
for(;i<3;i++){
fread(&temp,sizeof(employee),1,fp);
printf("工号:%d 姓名:%s 薪资:%g\n",temp.ID,temp.name,temp.salar
y);
}
fclose(fp);
return 0;
}
Fgets fputs
从指定文件中读取或者写入一个字符串
Char str[500] //fgets(str,n,fp) n 为指定读取字符的个数,但是fp只能读出 n-1 最后加’\0’
Fputs
Fprintf 和fscanf 格式化读写 注意:效率低,大量数据用 fread fwrite
无法划归到其他头文件中的
字符串,数字,产生随机数, 内存管理 系统通信 搜索排序等
参考: tarena课件
吊炸天c笔记
本文出自 “水滴石穿” 博客,请务必保留此出处http://liangge.blog.51cto.com/7154562/1896042
原文:http://liangge.blog.51cto.com/7154562/1896042