您的位置:首页 > 编程语言 > C语言/C++

C语言要点笔记

2016-03-25 21:26 351 查看
一.基础
1. 位运算补码(取反加一)是为了计算负数。

2. 编译原理:

源文件——.i文件——.s文件(汇编文件)——.o文件(二进制文件)——可执行文件(预处理——汇编——编译——执行)

3. Gcc(C语言编译器)+vim(linux自带的字符编辑器)

【eg. vim 文件名,gcc
文件名,./a.out(输出)】

4. C语言基础语法:

1)if嵌套最多15层,If语句一般三到四层,else if最多写7个,switch(里面的表达式只能是char和Int类型)。

2)循环语句的老祖宗Goto语句【语法:(声明变量,定义标签(:),if判断,goto
标签)】

二. 函数
1. 函数调用过程原理:

应用程序启动后(剩余)内存分配如下:

1)环境变量区:path,language...

2)栈区:执行代码段;弹栈压栈(先进后出);无论32位还是64位系统,栈的大小是固定的(2M),则如果声明一个结构体大小超过2M,则会造成内存溢出;

3)Static(静态区):

4)常量区:

5)代码段区:函数体...

2. ★(static)静态变量 全局变量

1)Static修饰的变量为静态变量,采用静态存储形式,但反过来,静态存储形式的不一定就是局部静态变量,例如全局变量也是静态存储形式。

2)静态变量分为全局静态变量和局部静态变量

全局静态变量与全局变量有区别:
虽然同为静态存储方式,但是全局静态变量失去了全局的“普遍含义”它所指的“全局”仅限制在本文件里,而全局变量却是各个文件可见的。
‚局部静态变量与局部变量有区别:
A.存储方式不同,前者为静态存储方式,后者为动态存储方式;
B.作用域是一致的,只局限于“模块”或者“代码段”;
©局部静态变量最大的特点就是作用类似于全局变量,而作用域类似于局部变量,(生命周期)与应用程序同生共死,在走出了某个函数或者代码段后生命周期延续,当再次回到这个函数或者代码段时,上次走出时的值仍然保存到现在,所以一般用它来做计数器。
3.自动变量(auto)和寄存器变量(register),外部变量(extern)
★变量类型用来说明变量所占空间的大小,变量存储类型用来说明变量的作用范围。
C语言变量存储类型有:
自动类型:不加则默认(局部变量)
‚寄存器类型:放在一个CPU寄存器中(数据在寄存器中操作比在内存中快),提高了程序代码执行速度。注意:取地址符&不能用于寄存器变量,它只能用于整型和字符型。
ƒ静态类型和外部类型
4.const修饰符【修饰只读变量(声明了const的变量是不能修改的)】
C语言中的Const放在不同位置有不同的作用,在不同情况下有不同用法。在此之前,开发者一直使用宏定义:#define VAR 100 来定义一下有特殊用途的类常量,不过因其存在一些劣势,const应运而生,后来便使用const int VAR=100 来定义类常量了。两种写法存储区域不同,前者放在常量区,后者放在栈区。
★★总结:
const声明的变量必须要进行初始化赋值,如果错过这个机会,以后就不能再给const的变量赋值了。
‚int const和const int,“颠倒写”都是可以的,但当const和指针掺和到一起时,“颠倒写”的规律可未必成立。
ƒconst和指针搭配是噩梦
eg1.
int main(){
int a = 5;
int b = 6;
//int const *p=&a;//const在*前面,修饰指向的对象,p可变,p指向的变量的值不可变
int * const p=&a;//const在*后面,修饰指针,p不可变(只读),p指向的变量的值可变
//const int *const p=&a;//指针p和p指向的对象都不可变
//p = &b;
*p = 100;
return 0;
}
结论:通俗的说,A指针可以随便指向一个整型,但只要被A盯上了的整型变量在使用*A引用时就不能修改了。
eg2.
int num=12;
int tmp=100;
const int *A=#
A=&tmp;
tmp=3
printf(“result=%d\n”,*A);//输出结果为3
return 0;
}
eg3.char *find_char(char const * source){
char *p=(char*)source;//强制转换
return p;
}
结论:即使A指向了tmp,虽然不能修改*A,但是仍然可以用tmp来修改这个值,不管*A
5.volatile 修饰符
volatile影响编译器编译的结果变量是随时肯发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错。
valatile可以保证对特殊地址的稳定反应,不会出错。
6.可变参数列表
eg. void fun(int a,...) //不知道a后面有多少个参数,写三个点。
7.递归函数(解决复杂问题)
8.程序结构(以函数为最小单位)
9.系统函数
随机数
rand()%100:%100表范围0-100,另外,可以srand((unsigned)time(NULL))为参照物。
‚Math.h
Sqrt():在gcc编译的时候要加-lm参数,把math库文件加进来。

三. 数组
字符数组:char[5]={‘h’, ‘e’ , ‘l’ , ‘l’ , ‘o’};结尾没有”\0”。
字符串数组:char[10]=”hello”;虽然使用双引号初始化,但是编译器会给数组的结尾加上”\0”(转义字符),表示结束。

四. 指针
1. 指针是保存内存地址的变量;可以用来存放任何已被定义的变量地址,即使他们没有被赋值。
eg.
int num=5;//定义Int类型的变量
int *p;(int*)p //声明一个Int类型的指针用来保存Int类型变量的地址
p=# //取num变量的地址放到p里面
printf(“%d\n,*p”);
指针变量 p
变量指针 *p //此处(声明后)加*(间接运算符)表示取指针里面的值,即用指针来访问值。

2. 空指针可以指向任何地址并对该地址的数值进行修改或者删除,所以需将其初始化为0。
3. 不同类型变量所占内存大小不同,指针只能保存与它类型相同的变量的内存地址。
【32位系统中所有类型的指针大小都是是4个字节(正好保存4G内存地址),64位系统中是8个字节】,(sizeof(指针))

4. 易混淆概念:指针地址,指针保存的地址和改地址的值。

5. 为什么使用指针(堆和栈的概念)
虽然通过变量名可以访问数据,但在操作大型数据和类时,由于指针可以通过内存地址直接访问数据,从而避免在程序中复制大量的代码,因此指针的效率最高,一般来说,指针会有三大用途:

1)处理堆中堆放的大型数据。

2)快速访问类的成员数据和函数。

3)以别名的方式向函数传递参数

★堆和栈

一般来说,程序就是与数据打交道,程序执行某一功能时将给功能所需数据加载到内存中,然后在执行完毕时释放掉该内存。

数据在内存中的存放形式:

1)栈区(stack):由操作系统自己分配并释放,一般存放函数和参数值,局部变量等。

其操作方式类似于数据结构中的栈。

2)堆区(heap):
由程序员分配并显示释放(一般用molloc,realloc,new等函数从堆中分配到一块内存),若程序员不释放程序结束时可能由操作系统回收。

注意:它与数据结构中的堆是两回事,分配方式倒是类似于链表。

3)寄存器区:用来保存栈顶指针和指令指针(用于控制程序中指令的执行顺序)

4)全局区(静态区 static):全局变量和静态变量的存储是放在一起的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和静态变量在相邻的另一块区域,程序结束后由系统释放。

5)文字常量区:存放常量字符串,程序结束后由系统释放。

6)程序代码区:存放函数体的二进制代码。

附注:★C语言的标准内存分配函数:malloc,calloc,realloc,free等。

malloc与calloc的区别为1块与n块的区别:

malloc调用形式为(类型*)malloc(size):在内存的动态存储区中分配一块长度为“size”字节的连续区域,返回该区域的首地址。

calloc调用形式为(类型*)calloc(n,size):在内存的动态存储区中分配n块长度为“size”字节的连续区域,返回首地址。

realloc调用形式为(类型*)realloc(*ptr,size):将ptr内存大小增大到size。

free的调用形式为free(void*ptr):释放ptr所指向的一块内存空间。

C++中为new/delete函数。

★★堆和栈的区别:

1)内存的申请方式不同:前者需程序员自己申请,因此也需指明变量大小;后者由系统自动分配。

2)系统响应的不同

对于栈,当栈的剩余空间大于所申请的空间,系统会为程序提供内存,否则提示栈溢出。

‚对于堆,系统收到申请空间的请求后会变量一个记录内存空闲地址的链表,找到一个空间大于所申请空间的堆结点时,就将该节点从接了内存空闲地址的链表中删除,并将该结点的内存分配给程序。然后在这块区域的首地址处记录分配的大小,这样使用free函数,delete(C++ )函数释放内存时,函数才能正确识别并删除该内存区域的所有变量。另外,所申请的内存空间与堆结点上的内存空间不一定相等,系统会自动将堆节点上多出的那一部分内存空间回收到空闲链表中。

3)空间大小的不同

栈是一块连续的内存区域,它的大小是2M,也有的说是1M,总之是一个编译时就确定的常数,是由系统预先根据栈顶的地址和栈的最大容量定义好的。

‚堆是不连续的内存区域,各块区域由链表将它们串联起来,它的上限是由系统中的有效虚拟内存来定的,因此获得的空间较大,获得方式也较灵活。

4)执行效率的不同

栈由系统自动分配,因此速度较快,但是程序员不能对其进行操作。

‚堆是由程序员分配的内存,一般速度较慢,而且容易产生碎片,不过用起来很方便。

5)执行函数时的不同

栈:先进后出原则

‚堆:效率比栈低的多,也容易产生碎片,好处是可以存储相当大的数据,并且一些细节也可以由程序员来安排

6. 内存泄露

简单的说就是申请了一块内存空间使用完毕后没有释放,表现为随着程序运行时间越长,占用内存越多,最终用尽全部内存,整个系统崩溃。由程序申请的一块内存,没有任何一个指针指向它,那么这块内存就泄露了。

五. 指针与数组
1. 用指针操作数组

2. 字符串:

strcat(连接),strlen(长度),strcpy(拷贝),strcmp(比较大小,相等返回0,不相等返回-1)

3. 命令行参数

在main函数的参数列表中可以写入形参:

Int main(int argc, char *argv[])

{

int i;

printf(“argc:d%\n,argc”);//以空格为单位分割

printf(“s%\n”,argv[0]”);//输出命令本身

for(i=1;i<argc;i++){

printf(“s%\n”,argv[i]”);//把输入的命令行参数打印出来

}

return 0;

}

六. 预处理与VT码(在未用windows界面早期使用命令时使用VT码)

1. #include 指令

#include “file.h” #include <file.h>

“ ”:编译器从用户的工作路径开始搜索(当前目录找不到会到系统库查找)

‚<>:编译器从标准库路径开始搜索

导入.h文件:是为了建立文件之间的联系,.h文件只是存放函数声明,比较小。

2. 条件编译

#if, #else, #endif, #ifdef, #ifndef, #undef(取消宏定义)

eg1. 多行注释:

#if 0/1(不显示/显示)

...

#endif

eg2.宏替换

#define OFF 0/1

...

OFF

eg3.

#ifndef _HHHH_H

#define _HHHH_H

...

#endif

//以上代码防止头文件被重复引用

3. 宏替换(#define
标识符(即符号常量) 字符串)//宏替换有问题,因运而生内联函数

★typedef 关键字【重新定义(数据类型)(eg. UINT
x ; //无符号整形 PINT p;//整形的指针)】

注:typeof还可以重新定义结构体(例如结构体嵌套中使用它重新命名结构体)或枚举等:

eg. Typeof struct date_st DATE或tepeof struct date_st{...}DATE;

★#define 定义swap(A,B):

1) {int temp=a; a=b; b=temp;}

这种方法最常见,也是最不容易出错的。

2){a = a+b; b = a-b; a = a-b;}

这种方法少了一个中间变量,缺点是有可能溢出。

3){a ^= b; b^= a; a ^= b; }

这种位运算方法速度快也不需第三个变量。

★补充:#号(双引号)和##号(连接字符串)的用法:
eg. define str(s1,s2) #s2#s2
//以字符串形式(加” ”)输出”s1””s2” ,如果s1,s2是string类型则直接输出。
#define slink(s1,s2) s1##s2 //s1,s2不能加” ”
【#define link(s1,s2) s1 s2 //s1,s2加” ”】
//无论s1,s2是字符还是int,##只是将s1,s2进行连接。

七. C语言模块编程

拆分文件,以多个文件编写C语言程序(头部引入头文件)。
eg: *.c *.h main.c

八. 静态链接库与动态链接库
//存放函数库的常用目录 /lib /usr/lib
//静态链接库:对函数库的链接是放在编译时期完成的,对象文件(.o)与牵涉到的函数库被拷贝到一个执行文件,通常文件名为libxx.a
(xx(库名))
//.so结尾的是动态链接库,.a结尾的是静态链接库

九. 指针的高级应用
1.指针变量赋值问题
int *a;
int *b;

★将指针b赋值给指针a,即a=b,之前要释放指针a所指向的内存空间,否则a的内存空间不再被访问,造成内存丢失。
★C语言规定指针只能指向类型相同的变量,指向不同类型变量的时候一定要进行强制类型转换。

2.指针用于数组
数组名与指针变量的区别:数组名是一个地址常量,数组名是不能改变的,而指针是一个变量,操作数组中的元素可以用指针实现。
‚指针越界错误(段错误:不再访问范围内)
ƒ数组与指针的区别:当用指针存储字符串的时候,字符串存储在静态存储区,此时字符串不能用指针修改。eg. Char *s=”Hello World”;
3.二级指针(指向指针的指针)
二级指针的值传递与指针传递。
eg.
#include <stdio.h>
#include<stdlib.h>
void init(int **p){
*p=malloc(4);
}
int mian(){
int *p=NULL;
init(&p)
*p=100
printf(“d%\n,*p”);
free(p);
retrun 0;
}
4.多级指针
5.函数指针(基本上作函数的参数)【可用来实现C语言接口】
eg.
#include<stdio.h>
int add(int a,int b){
return a+b;
}
int main(){
int(*cal)(int,int);//函数指针
cal = add;//将函数指针指向add函数
printf(“d%\n”,cal(1,2));
return 0;
}

十. 组合数据类型
1. 结构体类型
1)结构体定义:不同数据类型的变量的集合。
*结构体就是C语句,结束必须加分号。结构体内,字符数组成员赋值用strcpy()。
eg.
struct(结构体) student(类型名){...}; //结构体声明
struct(结构体) student(类型名) stu(变量名); //结构体使用
注:可在结构体声明时就定义一个结构体变量,可写在{...}前或{...}后。

2)结构体数组的使用跟普通数组一样。
eg.struct student stu[50]

3)★访问结构体成员:
结构体变量名.成员名
‚结构体指针变量->成员名
注:第一种是栈中变量定义的结构体,第二种放在堆里面,是使用剩余内存来开辟(molloc)的空间【结构体申请空间要在main()中】。如果结构体很大,里面涉及变量很多时用第二种方式。

4)结构体的嵌套

5)结构体中,char类型由占用一个字节变为4个字节【与前边对齐】。
在结构体结尾加上 __attribute__((packed))【不自动对齐】。
eg. #include<stdio.h>
sturct a_st{
char ch;
int i;
}attribute__((packed));//不自动对齐

int main(){
struct a_st A[10000];//如果自动对齐,声明此数组将会浪费很多空间
printf(“d%\n”,sizeof(stuct a_st));
return 0;
}
6)将结构体定义为指针类型
©用指针操作数组或字符串的时候,不能用sizeof()计算字符串或数组的长度,应为指针的大小是固定的。

补充:★class与struct的区别
*【structs过渡到class,C++是C的升级版。C语言的编译器gcc不支持class关键字,所以可用c++或g++编译。gcc也可以编译.cpp(c++)文件,但要求该.cpp文件格式是C的格式,调用库要用C语言的库去调用而不能用C++的库去调用】
*【eg.C++由很多特性:(源程序文件头部有:#include<iostream>,using namespace std;);(结构体使用时不用写stuct);(C++输出count<<..<<..<<endl;);等等】
*C语言编译器gcc最新版本支持在结构体里写函数,先前早期版本不行。
★用stuct(结构体),里面的成员属性和函数都是公共的,谁都能访问。而用class,要加修饰符,默认的是private:将它改成public:即可。
2. 枚举类型(经常作为函数 返回值 )
eg.
enum bool{false,ture}; //java中的ture和false就是通过枚举定义的
enum bool isNum(int n){...}

typedef enum status STATUS; //用typedef重定义(重命名)
enum status{FAIL=-1,NOLINK,ONLINK};//可以自己约定开始的值
STATUS isAction(){...}

int main(){
// enum bool b;
prinft(“d%\n”,false);//输出结果为0
prinft(“d%\n”,FAIL);//输出结果为-1
prinft(“d%\n”,ONLINK);//输出结果为1,则中间是0
}
*以上enum(枚举)类似宏(#define False 0),但是宏返回的是 int类型,而enum返回的是boolean类型。
3.类型定义 typedef
4.联合(union)
定义:将几个基本数据类型组合在一起(所有数据类型的空间都是在一起的)。
网络编程中使用广泛。

©位域(由于内存空间的发展,已经被淘汰了):
■位域只存储在char类型和int类型
■位域就是按位分配内存的结构体
■位域不能跨段(一段位域不能跨两个字节)
■不支持数组位域

十一. vin的使用
a:在光标后追加 A:在一行后追加 i:在光标钱面插入 I:在一行前面插入
s: 删除当前光标后插入 S: 删除整行后插入 o: 另起一行插入 O:在当前行上面插入
yy: 复制当前行 pp:粘贴当前行在光标的下一行 dd: 剪切当前行 u:撤销
nyy: 多行复制(n表示数字,从光标的位置开始向下复制n行)
ngg: 定位(n表示数字) gg:调到文件开头 GG:跳到文件的最后一行
查找:在正常模式下输入 / 所要查找的单词;next n:向下查找,N:向上查找
替换:(%表示整个文件,也可用具体行号范围如:0,40)%s/要查找的字符/要替换的字符
添加注释:(开头如上用具体行号)s/^/\/\/(^表示文件的开头,\位转义字符)
去掉注释:开头如上用具体行号)s/^\/\/(^表示文件的开头,\位转义字符)
自动补全:ctrl+p
查看多个源程序:vim 文件名1 文件名2 -o(小写o为上下屏,大写O为左右屏)
退出多个源程序: :qa 切屏:按两下ctrl+w
找到头部引入文件::sp(split ) 文件名 或者:vs(vsplit) 文件名

十二. gcc与gdb的使用
版本:gcc -v 帮助:gcc - -help 查手册:man
参数 ...

1)预处理:gcc -E
文件名(.c) -o
文件名(.i)

2)汇编:gcc -S
文件名(.i) -o
文件名(.s)(不写则默认生成.s文件)

3)编译:gcc -c 文件名(.s) -o
文件名(.o)(不写则默认生成.o文件)

注:vim生成的是文本文件,将.o文件转换成二进制文件:%!xxd
,返回原样: %!xxd -r

4)连接:gcc test.o -o test
可以直接执行第四步跳过前面3步

gcc其它参数:

-g: 添加程序的调试信息,然后可以使用GDB调试程序
(->gdb a.out)

eg. Start: 单步执行(->s) run:
执行完 bt:
查看栈,看有多少函数执行 n:
执行下一步

十三. ubuntu下的DDD调试工具的使用
用法和gdb一样,只是在gdb的基础上实现了可视化界面

十四. 文件操作
*C语言对文件的操作分为两种方式,即流式文件操作和I/O文件操作(前者调用标准库实现。后者调用内核函数库实现,在linux操作系统中,通过其提供的底层接口实现)

1. 流式文件操作

1) fopen()

fopen 的原型是:FILE *fopen(const char *filename, const char *mode),

fopen实现三个功能:为使用而打开一个流;把一个文件和此流相连接;给此流返回一个FILE指针参数;filename指向要打开的文件名,mode表示打开状态的字符串,其取值如下表:

“r” : 以只读方式打开文件

“r+”: 以读/写方式打开文件,如无文件则出错

“w”: 以只写方式打开文件(并清空文件内容)

“w+”: 以读/写方式打开文件,如无文件则生成新文件

“a”: 以追加方式打开只写文件,(文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留,如无文件则生成新文件)

“a+”: 以追加方式打开读/写文件,同上

FILE这个结构包含了文件操作的基本属性,对文件的操作都要通过这个结构的指针来进行,此种文件操作常用的函数及功能如下:

fgetc():从流中读取一个字符

fgets():从流中读一行或指定个字符

fputc(): 写一个字符到流中

fputs(): 写字符串到流

fseek(): 在流中定位到指定的字符(移动文件中的指针)

rewind(): 复位文件定位器到文件开始处

ftell(): 读取字节数

fread(): 从流中读指定个数的字符

fwrite(): 向流中写指定个数的字符

fprintf(): 按格式输入到流

ferror(): 发生错误时返回其值

feof(): 到达文件尾时返回真值

...

★fgets()

函数功能:用于从文件流中读取一行或指定个数的字符。

原型:char * fgets(char * string, int size, FILE * stream);

参数说明:

(1)string为一个字符数组,用来保存读取到的字符。

(2)size为要读取的字符的个数。如果该行字符数大于size-1,则读到
size-1 个字符时结束,并在最后补充' \0';如果该行字符数小于等于
size-1,则读取所有字符,并在最后补充
'\0'。即,每次最多读取
size-1 个字符。

(3)stream为文件流指针。

*【返回值】:读取成功,返回读取到的字符串,即string;失败或读到文件结尾返回NULL。因此我们不能直接通过fgets()的返回值来判断函数是否是出错而终止的,应该借助feof()函数或者ferror()函数来判断。

*注意:fgets()与gets()不一样,不仅仅是因为gets()函数只有一个参数
FILE *stream,更重要的是,fgets()可以指定最大读取的字符串的个数,杜绝了gets()使用不当造成缓存溢出的问题。

★fread和fwrite

函数功能:用来读写一个数据块。

一般调用形式:fread(buffer,size,count,fp); fwrite(buffer,size,count,fp);

参数说明:

(1)buffer:是一个指针,对fread来说,它是读入数据的存放地址。对fwrite来说,是要输出数据的地址。

(2)size:要读写的字节数;

(3)count:要进行读写多少个(次)size字节的数据项;

(4)fp:文件流指针。

*注意:1 完成读写(fwrite())操作后必须关闭流(fclose())。

★fprintf():按格式输入到流,其原型是int fprintf(FILE *stream, const char *format[, argument, ...]);其用法和printf()相同,不过不是写到控制台,而是写到流罢了。

★fseek()

函数功能:用来移动文件流的读写位置.

头文件:#include <stdio.h>

定义函数:int fseek(FILE * stream, long offset, int whence);

参数说明:

(1)参数stream为已打开的文件指针,

(2)参数offset为根据参数whence来移动读写位置的位移数。

参数whence 为下列其中一种:

(SEEK_SET 从距文件开头offset位移量为新的读写位置.

‚SEEK_CUR 以目前的读写位置往后增加offset个位移量.

‚(SEEK_END 将读写位置指向文件尾后再增加offset
个位移量.

当whence 值为SEEK_CUR
或SEEK_END
时,
参数offset
允许负值的出现.

*下列是较特别的使用方式:

1) 欲将读写位置移动到文件开头时:fseek(FILE *stream, 0, SEEK_SET);

2) 欲将读写位置移动到文件尾时:fseek(FILE *stream, 0, 0SEEK_END);

*返回值:当调用成功时则返回0, 若有错误则返回-1, errno
会存放错误代码.

*附注:fseek()不像lseek()会返回读写位置,
必须用ftell()取得目前读写的位置。

eg.

创建文件1.text (内容:ABC)

读取文件:

eg1.

#include<stdio.h>

int main(){

FILE *fp = fopen(“1.tex”,” r”); //r表示以只读方式打开文件1.text

char c = fgetc(fp);

printf(“c%\n”,c); //读取A

printf(“c%\n”,fgetc(fp));//第一次读取后指针往后移一位,则第二次读取B,同理第三次读取C,而第四次将输出空格

fclose(fp);

return 0;

}

注:可用循环结构实现上述打印

eg2.

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

int main(){

FILE *fp = fopen(“1.tex”,” r”);

char *p = molloc(100);

memcpy(p,”\0”,100); //此处不能用strcpy(p,0),”\0”在此表示填充

fgets(p,4,fp);//4表示读取的字节数(计算机最小单位是字节而不是位)

printf(“s%\n”,p);

putchar(‘\n’); //去掉空格(按原格式读取)

free(p);

fclose(fp);

feturn 0;

}

补充:★strcpy和memcpy

■strcpy和memcpy都是标准C库函数,它们有下面的特点:

strcpy提供了字符串的复制。即strcpy只用于字符串复制,并且它不仅复制字符串内容,还会复制字符串的结束符。【已知strcpy函数的原型是:char*
strcpy(char* dest, const char* src);】

memcpy提供了内存地址的复制。即memcpy对于需要复制的内容没有限制,因此用途更广。

■strcpy和memcpy主要有以下3方面的区别:

1)复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。

2)复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。

3)用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy。

eg3.

#include<stdio.h>

int main(int argc , ch ar*argv[ ]){

FILE *fp = NULL;

int size = 0;

if(argc < 2){

return 1;

}

fp = fopen(argv[1] ,” r”); //命令行读取第一个参数

fseek(fp, 0 , SEEK_END); //把fp从开头移动到结尾

size = ftell(fp); //ftell()表示读取字节数

printf(“file size:d%\n”, size);

fclose(fp);

feturn 0;

}

eg4.

#include<stdio.h>

int main(int argc , char*argv[ ]){

int size = 0;

FILE *fp = NULL;

char *str = NULL;

fp = fopen(argv[1] ,” r”); //命令行读取第一个参数

If(fp == NULL){ //做判断,如果文件不存在就退出

perror(“error”);

retrun 1;

}

//perror( ) 用来将上一个函数发生错误的原因输出到标准设备(stderr)。(不可以丢了#include<stdio.h>这个头文件,perror是包含在这个文件里的)

fseek(fp, 0 , SEEK_END); //把fp从开头移动到结尾(0—SEEK_END)

size = ftell(fp); //ftell()表示读取字节数

rewind(fp);//复位指针

str = malloc(size+1); //size+1: 包括”\n”

memcpy(str , “0” , size+1);//第二个参数是个地址

fread(str , size , 1 , fp); //数字1表示读1次

str[size]=’\0’; //读完后将其终止

printf(“s%\n”, str);

fclose(fp);

Free(str);

feturn 0;

}

十五. const_extern_static修饰符详解
1. extern称为外部变量。为了使变量除了在定义它的源文件中可以使用外,还要被其它文件使用,因此,必须将全程变量通知每一个程序模块文件,此时可用extern说明。

2. .c文件中static修饰的变量或方法只限制在本文件里访问,加extern关键字也访问不了。

3. 不要在头文件(.h)文件中用static关键字修饰变量或方法(基本上关键字都写在实现文件(.c)里面)。

十六. 动态数组

十七. Makefile的使用
创建test.c文件

eg . 编写Makefile文件:

all:test //目标条件

test:test.o //依赖(.o)文件,
:表示依赖关系

gcc test.o -o test

test.o:test.s

gcc -c test.s -o test.o

test.s:test.i

gcc -S test.i -o test.s -std=c99

test.i:test.c

gcc -E test.c -o test.i

执行:make all

clean: //处理(删除)命令

rm -rf *.i *.o *.s

执行:make clean (不写clean,默认是执行第一个all)

直接生成汇编:make test.s

(可用变量替换的方式)修改程序:

TARGET=test

OBJ=test.o

All:$(TARGET)

$(TARGET):test.o

gcc test.o -o test //可写成:gcc $^ -o $@,$^指代依赖文件(test.o ) ,S@指代目标文件($(TARGET))

...

也可跳过预处理和汇编:(注释语句用#)

TARGET=test

All:$(TARGET)

$(TARGET):$(OBJ)

gcc $^ -o $@,$^

test.i:test.c //可用%代替test,写成%.i
: %.c,%代表当前文件,此外*代表当前文件夹

gcc -c test.c -o test.o //同上可写成:gcc -c $^ -o $@

clean:

rm -rf *.i *.o *.s

.PHONY:$(TARGET) all //不管程序代码是不是最新的(有没有变动)都从新编译
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: