gcc和gdb
【1】GNU工具
编译工具:把一个源程序编译为一个可执行程序
调试工具:能对执行程序进行源码或汇编级调试
软件工程工具:用于协助多人开发或大型软件项目的管理,如make【2】gcc简介
全称为GNU CC ,GNU项目中符合ANSI C标准的编译系统
【3】gcc编译过程
1--- 预处理:主要进行宏替换以及头文件的包含展开
gcc -E HelloWorld.c -o HelloWorld.i
2--- 编译:编译生成汇编文件,会检查语法是否有错误
gcc -S HelloWorld.i -o HelloWorld.s
3--- 汇编:将汇编文件编译生成目标文件(二进制文件)
gcc -c HelloWorld.s -o HelloWorld.o
4--- 链接:链接库函数,生成可执行文件
gcc HelloWorld.o -o HelloWorld
【4】Gdb调试
首先使用gcc对file.c进行编译,注意一定要加上选项‘-g’
查看文件(list)
(gdb) l
一次十行,知道显示完为止
l 1 回到先前的位置
设置断点 (break)
(gdb) b 行数
删除断点 (delete)
del 1删除第一个断点
查看断点情况
(gdb) info b
查看变量值(print) 也可以查看变量的地址 p &a
(gdb) p n
单步运行 (next step)
(gdb) n
(gdb) s 进入函数
恢复程序运行 (continue)
(gdb) c
帮助
(gdb) help [command]
退出
q
gdb使用时注意事项
在gcc编译选项中一定要加入‘-g’。
只有在代码处于“运行”或“暂停”状态时才能查看变量值。
设置断点后程序在指定行之前停止
运行被调试程序,设置所有的能影响该程序的参数和变量。
保证被调试程序在指定的条件下停止运行。
当被调试程序停止时,让开发工程师检查发生了什么。
根据每次调试器的提示信息来做响应的改变,以便修正某个错误引起的问
题
***************************指针***********************
【1】指针定义
在计算机内部存储器(简称内存)中,每一个字节单元,都有一个编号,称为地
址。
在C语言中,内存单元的地址称为指针,专门用来存放地址的变量,
称为指针变量(pointer variable)。在不影响理解的情况中,有时对地址、指针和指针变量不区分,通称指针。
*:在定义指针变量时,只起到标识作用,在其他情况下,代表获取指针变量内的内
容
&:代表取变量的地址
int *p = &a;
//如果一个指针变量指向NULL,代表不给他分配任何地址
int *q = NULL;
printf("q = %p\n", q);
输出结果为:q=(nil)
//指针变量只能指向一块已经开辟的空间
//int *n = 0x12345678;
错误,变量的地址只能由系统分配,不能人为指定
//地址的运算与数据类型相关
printf("p = %p\n", p);
printf("p + 1 = %p\n", p + 1);
【2】指针与一维数组
//数组名是一个地址常量,不能改变地址
int a[6] ;
a++; 错误,a为地址常量,不可更改 int b[N];
b = a; 错误,b为地址常量,不可更改
指针的升级 int a[6] ; &a 代表整个数组a的地址,&a+1 代表移动整个数组的大小
printf("&a = %p\n", &a);
printf("&a + 1 = %p\n", &a + 1);
【3】指针与二维数组
1)指针的升级 &a 代表整个数组,&a+1 代表移动整个数组的大小 int a[3][4];
printf("&a = %p\n", &a);
printf("&a + 1 = %p\n", &a + 1);
2)二维数组的名字为行指针,指向a[ 0 ] 元素,a+1每次移动一行元素的大小 printf("a = %p\n", a);
printf("a + 1 = %p\n", a + 1); 3)指针的降级,将行指针降级为列指针
*a 代表将行指针a降级为列指针,指向元素a[0][0],*a+1,移动一个元素的大小 printf("*a = %p\n", *a);
printf("*a + 1 = %p\n", *a + 1);
4)a[0] 为列指针,指向元素a[0][0], a[0]+1,移动一个元素的大小
printf("&a[0][0] = %p\n", &a[0][0]); printf("&a[0][0] + 1 = %p\n", &a[0][0] + 1);
【4】字符指针和字符串
1)字符串自带结束标志符‘\0’
char s1[] = "hello";
char s2[6] = {'h', 'e', 'l', 'l', 'o', '\0'};
char s2[5] = {'h', 'e', 'l', 'l', 'o'}; 数据后没有结束符,易发生越界访
问
2)字符指针指向一个字符串常量,不可更改字符串的内容,但是可以更改字符指针的
指向
【5】数组指针
数组指针:本质上一个指针,指针指向一个数组,就是一个行指针
int (*p)[4]; //4为列数
【6】指针数组
指针数组:本质上是一个数组,数组里面存放的是指针
int *p[2]; // [2] 为数组的长度,表示数组内可以存储两个指针
【7】多级指针
多级指针:指向指针的指针
int *p = &a; int **q = &p; 【8】const
const常用来修饰指针变量或者类型
1)如果const修饰类型,则不能通过指针变量修改数据 const int *p = &a;
*p = 40; 错误,不可通过*p访问数据内容
2)如果const修饰一个指针变量,则不能呢个改变这个指针变量的地址
int *const p = &a;
p = &b;错误,不可更改p的指向注意:const 修饰谁,谁被常量化,不可更改
******************函数********************【1】定义
函数是一个完成特定功能的代码模块,其程序代码独立,通常要求有返回值,也可以是空值。
【2】一般形式如下:
<数据类型> <函数名称>( <形式参数说明> )
{
语句序列;
return (<表达式>);
}
其中:
<函数名称>是一个标识符,要求符合标识符的命名规则;
<数据类型>是整个函数的返回值类型,如无返回值应该写为void型;
<形式参数说明>是逗号”,”分隔的多个变量的说明形式,通常简称为形
参;
大括弧对 {<语句序列> },称为函数体;
<语句序列>是大于等于零个语句构成的。
注意:在函数体中,表达式语句里使用的变量必须事先已有说明,否则不
能使用。
return(<表达式>)语句中表达式的值,要和函数的<数据类型>保持一致;如函数的<数据类型>为void,可以省略或者无表达式结果返回(即写成
return ;)。
【3】函数传参
值传递 :函数的传参1:值传递,只是将变量的数据传递给行参,不会改变原来实参的数据
地址传递 将变量的地址传递给行参,改变地址的内容,则实参也会改变
注意:数组的值传递,实质为地址传递,改变形参的值,实参的值同样被改变【4】命令行传参(向main函数传递参数)
argc:表示命令行传参的个数
argv:表示命令行所传的每一个参数
【5】函数指针
函数指针:本质上是一个指针,指向一个函数
注意:函数名就是首地址
【6】指针函数
指针函数:本质上是一个函数,返回值是一个指针
【7】函数指针数组
函数指针数组:本质上是一个数组,数组里面存放的时函数指针
【8】递归函数
在递归函数中判断是否满足某个条件,不满足则return 递归函数本身
(return myrecursion)
满足条件则返回一个准确的数值
int myrecursion(int n){
if(n<1)
return 1;
else
return n*myrecursion(n-1);
}
【9】回调函数
将一个函数以参数的形式传递给某个函数。
即回调函数的其中之一或更多的形参是某个函数传参使用函数名
int callback(int fun(int a,int b),int m,int n){ return fun(m,n);
}