C语言基础

1.     gcc  -o  1 1.c  将1.c编译生成编译后的文件名1

gcc  -o *.c代表编译所有的c文件

         执行二进制程序用./1就行了

         Gcc  1.c

         执行 ./a.out(默认生成)

         .c→.i(预处理gcc -E)→.s→.o→.exe

         gdb调试流程,调试运行时的错误:

                  gcc–g test.c –o test 

//进入调试模式后第一个命令是l(一次10行查看调试代码)

设置断点: b 6(第6行)

查看断点情况: infob  //del 1删除第一个断点,2就是第二个

运行代码: r

查看变量值:p n(变量)

单步运行:n(下一步)   s(进入到函数)

恢复程序运行:c//从一个断点跳到另外一个断点

通过命令行传递参数:set args 参数1   参数2

帮助:helpcommand

                  gdbtest

2.     编辑:gedit和vi模式

条件编译:

          第一种:#ifdef 

                                    …

                            #else

                                    …

                            #endif

          第二种:#if

                            #else

                            #endif

3.     Vim编辑器的使用:

1)     :r 文件名   读入一个文件内容,并写入当前编辑器

2)     :w 文件名  将当前文件的内容写入到一个新的文件中

3)     :w         保存的意思

4)     :!指令     暂时离开vim去执行指令

5)     :sh         回到shell,执行完ctrl+d可以回到vim

6)     在一个vim下输入vsp 2.c(文件名),同时打两个

低行模式,输入看不见,直接执行:

1)     dw  删除单词  dd  删除一行  H 移动屏幕第一行  M移到中间一行 

L  移到屏幕最后一行  G  移到文件最后一行   0 移到当前行开头

$  移到当前行最后一个字符

dd  p:剪切粘贴   yy  p:复制粘贴   gg=G  自动对齐

shift+v+up(down) 从当前行往下全复制  p粘贴

shift+zz  退出

4.     预处理:头文件的替换,宏的替换,注释的取消

gcc –E 1.c –o 1.i

         编译:将1.i文件通过编译器变成汇编代码(语法检查)

                          gcc–S 1.i –o 1.s

         汇编:将汇编代码生成目标文件(可重定向文件)

                          gcc–c 1.s –o 1.o   hexdump –C 1可以查看二进制文件

         注释:if 0开始   endif结束

5.     一个int存的最大数为232  //objdump 1 -Mintel -S > a.S  将目标文件转换为汇编文件

vi a.S查看

/main是搜索main字符

6.     scanf(“%d”,&i);  //标准输入,从终端上输入字符流到了字符串中

其中&i地址符号&是c编译系统分配的,

scanf中不能加\n,因为scanf要求有什么就输入什么

#define MAX 10预处理阶段 ,一般写在函数外面

const int MAX = 10;   只读变量,可读不可写

const和define及typedef的区别:

          define是在预处理阶段展开,const是在编译运行阶段展开,编译时确定其值;

          define没用类型,不进行类型检查,替换时可能出错, const常量有具体类型

                   在编译阶段会进行类型检查;

define只是进行展开,定义的宏常量有多个备份在内存里(使用时宏替换,不断分配内存),const的只读变量只有 一个备份,分配一次后不再分配

typedef char *string_t定义一个类型的别名,有类型检查,在编译期处理。

7.     类型转换:由小转大可以(float转int),大转小不行(内存溢出)

Int占4个字节,内存虚拟成一个个地址,int占4个,char占一个,赋值一个int变量地址是随机的

8.     宏替换:

        1)不带参数的宏定义:格式: #define 标识符 字符串 如df PI 3.14
        2)带参数的宏定义:  格式: #define 宏名(参数表) 字符串
                         如: #define S (a,b) a*b,即S(3,2)= 6
        注意:“”里的东西不会被宏替换
 

9.     逻辑表达式与逻辑运算符

选择语句:if语句和switch语句

循环语句:while    do-while    for

跳转语句:break    continue    goto   return

                    break  continue   goto 一般与if连用

break 与 continue 与goto与return与exit的区别?

         break 直接跳出本次循环(只能跳一次,不能跳出多个嵌套循环);continue只是跳出本次循环;goto跳出嵌套循环,但是要与lable合用,如:for()goto 1;1:

goto可以跳到lable的地方继续往下执行,但是不能跳出函数体;return是退出当前函数,返回到调用处,void函数直接return可以退出;exit是直接结束进程,不往下执行了。

逻辑表达式: <   >  <= >=  ==  !=  (主演和赋值语句=区分)

         if(a>1&&a<5)不能写成if(1

         1

逻辑运算符:!非   &&与(可以理解为乘法)  ||或(可以理解为加法)

异或:0^0 =1  按位取反 : ~1=0  左移:《(移位运算如果是左移n位,将该数乘以2的n次方,右移就是除)

10.  switch语句

格式:

switch(表达式){

         case常量表达式1: 语句1; break;

         case常量表达式2: 语句2; break;

         …

         case常量表达式n: 语句n;   break;

                          default:语句n+1;}    //注意case后面可以有多条语句,可以不用大括号,但是要有break跳出switch语句。

11.  循环语句

while和for

while( )  true进入循环体,false退出

a. 循环一定要有循环条件变量i

b. 一定要有范围

c.  一定要达到这个范围(累加或累减)

for(表达式;表达式;表达式)更简洁

12.  数组(数组名是数组的首地址)

sizeof( int ) ,  计算对象所占用的字节数,char*指针变量占8个字节(64位,32位4个字节) 

getchar()等同于scanf(),但是更有效率,putchar()同理

数组a[N] 其中N一定是个常量,不能是变量;

根据内存图可知数组的地址是连续的,开辟了一个连续的地址空间,下标和索引用来访问数组元素。注意不能把一个数组赋值给另外一个数组,因为数组的地址是一个只读的地址。a[ ] 的元素默认为0。

                  sizeof(数组名)求的是数组占用字节数,sizeof(a[1])是求一个元素占用的字节数

13.  二维数组

二维数组的命名方式:可以写成a[3][3]={{1},{2},{3}},没给出的默认为0,如果对全部元素赋值了,那可以写成a[][3]的形式,第一维长度可以不填。

二维数组可以理解为多个一维数组,就是每个一维数组的元素都是一个数组。

14.  函数

概念:不是数学上的函数,是指一个功能模块;一个函数就是划分一小块功能,便于修改和调式,避免重复的多次使用代码。

格式:返回类型(void就是没有返回值)   函数名(参数1  , 参数2)

                  实参:函数调用的参数,可以传入变量,常量,运算的变量;

实参是通过值传递的,计算实际参数的值赋值给形式参数,参数传递的时候创建副本。数组传递直接传递数组名即数组首地址即可。

                  形参:函数定义的参数。  //形参实参类型最好一致

                  return后面跟着的语句可以被调用函数所接受

函数的声明:

                  格式:int  sum(int a ,int b);//封号不能漏,在main上方声明

                  如果一个函数体放在main函数下面的话,一般出现函数无法调用的错误,这时候就需要函数声明。

15.  递归

函数调用其本身称为递归。//递归一定要有出口!就是递归到最后要return一个值。

16.  局部变量和全局变量

局部变量:自动存储变量,在函数返回的时候会被自动回收。//形参也是局部变量。

全局变量:从变量的声明开始到程序结束。

局部静态变量:作用域是函数内部,值是保存到函数结束。static int a=0;

静态全局变量:只能作用于本文件,其他文件不能导入。

extern I;代表导入一个变量。在同时执行的文件。gcc –o 1 *.c

栈:局部变量和函数参数存放在里面,自动释放;

堆:new分配的内存块,由程序去控制释放;

自由存储区:和堆类似,malloc分配,free释放;

常量区:存放常量,不许修改。

17.  指针

格式:int *p =&a;(这样定义可以清楚的知道指针变量p就是等于a的地址)

概念:指针就是存放一个变量的地址!p=&a;*p=a地址存储空间中存放的值!//其实定义指针变量*和指针*可以理解为不同的符号,如果把定义*改为%就好理解了。

指针变量也是变量,所以也有声明和初始化。

i=*p++相当于i=*p;p++;

间接运算符(重点):间接赋值是指针的重点!*p就是a的值,p就是a的地址!

18.  指针的用途

把指针作为形式参数,间接引用,传递的是地址,实参会改变,参数改变发生在栈销毁之前;

注意和参数传递不同:参数仅是创建了一个副本,实际参数不会改变。

指针可以加减,不可乘除。

指针的偏移与指针的类型相关,指针类型占几个字节,偏移几个字节。

//两个指针相减等于两个指针间的距离(位数)除以指针类型所占字节数。

19.  const

const  int* p;  //间接引用的值不能改变,地址能改变,*p=2不可以(*p只读),可以p++;

const  *int p;  //p++不可以,*p=2可以改变

主要是看const修饰的是*p还是p,修饰谁,谁就不能改变

int a[];   int b[]; a=b;是错误的,因为数组地址是只读的。

20.  指针和数组的绑定

数组名是只读地址,只需要指向数组的首地址就可以了,绑定了之后就可以像数组那样访问了。//数组作为函数参数传递,其实传递的就是指针(数组首地址),所以无法确定长度。

21.  字符串

英文”aaa”,字符串末尾会默认加\0,所以”aaa”占4个字节。”\0” ascii 为0,0的ascii为48。

字符串的初始化:

         char[5] = {‘a’,’b’,’c’,’d’,’\0’}  与char[5] = “abcd”一样。编译期会自动在数组空余位添加\0。//%s输出字符串

字符串的读取格式化参数是%s,scanf不能取地址,scanf参数是指针。如char a[10];scanf(“%s”,a);

scanf 和gets的区别:遇到空白或回车结束读取,gets是一遇到回车就结束。scanf不能读入空格,读入空格代表字符串读取完成。

printf和puts的区别:puts会自动加\n。

字符串和字符指针:

                          char  a[] =  “abcd”;

                          char  *a =  “abcd”;

字符串存在一个只读字符串常量区,指针式指向字符串常量区域,不能修改只读区域数据;而数组是由字符串常量区拷贝到内存数组中,所以可以修改。

22.  字符串常用api

字符串api需要导入#include头文件

char *strcpy( a,b);//把b字符串复制到a

int strcmp(a,b);//字符串a与b是否相等,返回0代表相等,1代表不相等

charstrcat(a,b);//把字符串b中拷贝到a中,接在a后面,注意a的字符串长度是否满足条件。

int strlen(char*s)//求字符串的长度,数\0之前出现了多少个字符

void*memcpy(void *dest, const void src, size)//内存复制到另一块内存

void *memset(void*s, int c, size)//内存清空,size是多大,调用端可用sizeof()得到大小,将s中当前位置后面的size个字节用c替换并返回s;

memset($stu[i],0,sizeof(stu));//其中stustruct  student stu{},用0替换stu[i]所占字节,也就是将stu[i]数据删除。

void*指针(c语言的泛型),万能指针,因为它可以指向任意一个数据类型。

23.  二级指针

int **p;   地址:*p/p[0]   间接引用的值:**p/p[0][0]/*p[0]

可以这么理解:指向一维数组的指针为一级指针,指向一级指针(一维数组)的指针为二级指针。

二级指针作为参数传递:

         一级指针作为参数的时候是改变引用的值,二级指针传参改变的是地址。

二级指针的遍历:

char *p[] = {“abc”,””def”,”hi”};

for(i=0;i<3;i++){printf(“%s”,p[i]);)

24.  常识操作

int a = s[0] -'0';  //s[0]是char类型,用s[0]的ascii码减去‘0’的ascii码得到int型s[0],常用在数字型字符串

                  全局:是在一个路径下都能访问

                  局部:只能在可执行程序的路径下访问,并且要加./

                  命令行参数:就是加在可执行程序后面的参数//如ls、cd都是程序

main函数也要传递参数  int main(int argc参数个数,int *argv[]);注意传递参数的末尾是\0。

atoi(c)将字符转化为整形

预处理阶段:文件包含,宏替换。

文件包:含就是由#include定义的文件

宏替换:由#define定义的指令。//尽量在宏的参数上加括号,防止优先级问题。

预处理的指令:(预处理→编译生成汇编语言→汇编成机器语言)

gcc -E 1.c -0 1.i

注意:不能把预处理指令与定义变量作比较,预处理仅仅是替换而已。而且不检查语法规则。

#:字符串化   如#define S(a) #a,其实就是将变量a上面加了个引号“a”,不负责运算。

##: 符合拼接的意思,如#definefunc(a)  func##a 替换后变成了funca

__LINE__显示所在的行,__FUNCTION__显示所在的函数名,__FILE__显示所在的文件名称.// 两个下划线

printf("line:%d func:%s file:%s\n”,_LINE_,_FUNCTION_,_FILE_);

程序调试的时候用打印

25.   结构体

结构体就是不同类型成员的集合。

结构体的声明:

         struct  ZUO{          struct  ZUO{                    struct{

                          intx;                                            intx;                          int x;

                          inty;                                            inty;                          int y;

                          intz;};                                        intz;}aa={1,2,3};     int z;}aa={1,2,3};

成员变量就是结构体里面的元素,结构体也是一个构造函数。

第一种struts ZUO是类型 ,第二种aa是struts ZUO定义的类型,第三种aa是此结构体定义的变量,这种只能定义一个变量,一般用于内嵌结构体。

初始化:第一种 struct ZUO aa={1,2,3};第二种、第三种如上,用的少。

对结构体数值型成员赋值zuo.x = 10; 结构体可以赋值,但是类型要一致,比如都是ZUO类型。

结构体传参:

voidchange(struct ZUO* p){ p->x=10;}  格式:结构体指针->结构体成员

结构体字符串赋值用strcpy(aa.name,“hi)

注意:不能将一个结构体变量作为一个整体引用,要对成员分别应用

26.  共用体和枚举

linux操作系统以4个字节进行内存对齐。内存是如何对齐的:编译器根据类型大小填充字节数,一般是4个字节的整数倍。如果不满4个字节,以4字节填充。超过,就以4个字节对齐。

对齐的理由:保证移植性和性能。保证移植的时候不会出错;保证cpu对内存访问只访问一次,而不是多次。

结构体数组的初始化:

struct stu st[10];

strcpy(st[0].name,"zhangsan"); 

stu[0].age = 16;

================================

strcpy(st[0],"nan");

union AA{

int a;

int b;

};

说明联合只有一个成员存在,联合的长度以最长的数据类型算。

枚举:enum A{N=10};等同于 #define N 10  和 const int N=10;

枚举中间是逗号:如enumcolor{red=1,yellow=2,blue=3};

枚举有个奇怪的地方就是使用时在main函数可以直接定义一个枚举变量后,就可以直接用枚举种的参数,如同#define替换。

27.Make

工程管理器,能够管理较多的文件。Make可以根据文件时间戳自动发现更新过的文件而减少编译的工作量。同时,它通过读入Makefile文件的内容来执行大量的编译工作。//Make只编译改动的代码,而不用完全编译。

你可能感兴趣的:(C语言)