上来先说一下Linux下的gcc的基本用法:
gcc –o main.c main.out //编译main.c成可执行文件main.out 参数-o不能gdb调试
gcc –g main.c main.out //编译main.c成可执行文件main.out 参数-g可以gdb调试
gdb ./main.out(gdb main.out) //调试main.out程序
然后是gdb的基本调试方法:
gdb命令 | 作用 |
l/list | 查看源代码,默认显示10行,可以再l一下显示所有源代码 |
回车键 | 执行上一个命令 |
break+数字 | 设置断点,数字为行数 |
start | 开始单步调试 |
n/next | 执行下一行代码 |
s | 进入函数 |
p 变量名 | 查看变量的值(print) |
bt | 查看函数的堆栈 |
f 数字 | 切换栈 |
q | 退出调试 |
指针:一个变量的地址 (任何类型的地址都是一样的,4个字节)
指针变量:专门存放变量地址的变量
指针类型决定步长,决定解析方式
内存由操作系统统一管理,系统认为用户只要48位内存,系统内核要16位内存
指针变量就是一个内存地址,变量名是一个代号,变量的本质是内存
数据段保存着变量,如全局变量,常量
C语言语法不允许直接操纵代码段,汇编和机器语言可以。代码编译后放在代码段
程序运行的状态信息保存在栈内存中,堆和栈内存里才可以写入(预留空间才可写入)
GCC会对内存变量分配进行优化:同一种变量类型会放到一块儿
32 位内存地址指针占 4 个字节,64位操作系统内存地址指针占用8个字节
栈内存地址:先声明的地址大,后声明的地址小(先进后出),与代码段数据段相反
函数指针常常在回调函数中使用
p pa : 打印pa的内存地址
p &pa:打印pa本身的地址
p *pa : 打印pa内存地址中的内容(通过地址取值)
c语言不对指针合法性进行检查
工具gdb内的指令格式:
-
x/3d 0×7ffffffde14 //以十进制连续输出de14地址后3个数值
-
x/:表示连续输出地址内的值
-
3:表示输出3个地址内的值
-
0×7fffffffde14:表示三个连续地址里的第一个地址
-
d:表示连续输出的值用十进制表示
p[3] 相当于 p+=3 , 表示内存地址向后移动三格 (内存偏移)
数组本质上是指针常量,指针是变量。因此数组能做的事情指针变量都能做,指针能做的事情数组不一定能做。数组当作内存地址输入的话,可以直接当作参数传进去,不用加&取址符
void main()
{
int num = 20;
int *p = # //指针存储地址
printf(“%d %d”,*p,num); //运行结果 20 20 ,*p与num等价
printf(“%d %d”,*p,num); //运行结果 输出两个地址 ,值相等,不等价
}
定义指针变量
类型名 * 指针变量名(int p1,p2;)
在定义指针变量时要注意,指针变量前面的“*”表示该变量的类型为指针型变量.指针 变量名是p1和p2,而不是*p1和*p2。这是和定义整形或实型变量不同的.
引用指针变量
在引用指针变量时,有以下3种情况:
(1)给指针变量赋值.如:
p=&a; //把a的地址赋给指针变量p
指针变量p的值是变量a的地址,p指向a
(2)引用指针变量指向的变量。
如果已经执行p=&a;即指针变量p指向了整形变量a,则
printf("%d",*p);
其作用是以整数形式输出指针变量p所指向的变量的值,即变量a的值。
如果有以下赋值语句:
*p=1;
表示将整数1赋给p当前所指向的变量,如果p指向变量a,则相当于把1赋给a,即a=1;.
(3)引用指针变量的值.如:
printf("%o",p);
作用是以八进制数形式输出指针变量p的值,如果p指向了a,就是输出了a的地址,
即&a。
指针变量作为函数参数
函数的参数不仅可以是整形,浮点型等数据,也可以是指针类型。他的作用是将一 个变量的地址传送到另一个函数中。
如果想通过函数调用得到n个要改变的值,可以这样做:
(1)在主调函数中设n个变量,用n个指针变量指向它们;
(2)设计一个函数,有n个指针形参,在这个函数中改变n个形参的值;
(3)在主调函数中调用这个函数,在调用时将这n个指针变量作实参,将他们的地址
传给该函数的形参。
(4)在执行该函数的过程中,通过形参指针变量,改变它们所指向的n个变量的值;
(5)主调函数中就可以使用这些改变了值的变量了。
数组:
在c语言中,数组名(不包括形参数组名,形参数组并不占据实际的内存单元)代表数组中首元素(即序号为0的元素)的地址。因此,下面两个语句等价:
p=&a[0]; //p的值是a[0]的地址
p=a; //p的值是数组a首元素(即a[0])的
注意:数组名不代表整个数组,只代表数组首元素的地址。上述p=a;的作用是“把a数组的首元素的地址赋给指针变量p”,而不是“把数组a各元素的值赋给p”。
在指针指向数组元素时,可以对指针进行以下运算:
· 加减一个整数,如p+1;或者p-1;
· 自加运算,如p++或者++p
· 自减运算,如p--或者--p
(1) 如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素,
p-1指向同一数组中的上一个元素。注意:执行p+1时并不是将p的值(地址)简单地 加1,而是加上一个数组元素所占用的字节数。
(2)如果p的初值为&a[0],则p+i和a+i就是数组元素a[i]的地址,或者说,他们指向a数组
序号为i的元素,见下图,这里注意的是a代表数组首元素的地址,a+1也是地址,
它的计算方法同p+1,即它的实际地址为a+1*d。例如,p+9和a+9的值是&a[9],它
指向a[9]。
(3)*(p+i)和*(a+i)是p+i或a+i所指向的元素,即a[i]。例如*(p+5)和*(a+5)就是a[5],三
者等价.
(4) 根据以上叙述,引用一个数组元素,可以用下面两种方法:
(5) (1)下标法,如a[i]的形式;
(2)指针法,如*(a+1)或*(p+i)。其中a是数组名,p是指向数组元素的指针
变量,其初值p=a。
高级用法
(1)
p++;
* p;
p++使p指向下一个元素a[1].然后若在执行* p,则得到下一个元素a[1]的值。
(2)
*p++;
由于++和*同优先级,结合方向为自右而左,因此它等价于*(p++)。先引用p的值,实
现*p的运算,然后再使p自增1.
(3) *(p++)与*(++p)作用是否相同?答案肯定是不相同的。前者是先取*p的值,然
后使p加1.后者是先使p加1,再取*p。
指针与字符串: 在c语言中只有字符变量,没有字符串变量。
字符指针作函数参数
假如想把一个字符串从一个函数“传递”到另一个函数,可以用地址传递的办法,即用字
符数组名作参数,也可以用字符指针变量做参数。在被调用的函数中可以改变字符串的
内容,在主调函数中可以引用改变后的字符串。
使用字符指针变量和字符数组的比较
用字符数组和字符指针变量都能实现字符串的存储和运算,但它们两者之间是有区别的,主要为一下几点:
(1)字符数组由若干元素组成,每个元素中放一个字符,而字符指针变量中存放的是地
址(字符串第1个字符的地址),绝不是将字符串放到字符指针变量中。
(2)赋值方式。可以对字符指针变量赋值,但不能对数组名赋值。
对字符指针变量赋值:
char *a;
a="I love bols!"; //将字符串首元素地址赋给指针变量,合法。但是赋给a的不是字符串,只是一个字符串首元素的地址。
//不能用以下办法对字符数组名赋值:
char str[14];
str[0]='I'; //合法,对字符数组元素赋值
str="I love cangls"; //非法,数组名是地址,是常量,不能被赋值
(3)存储单元的内容。编译时为字符数组分配若干存储单元,以存放各元素的值,而对
字符指针变量,只分配一个存储单元。
(3)用字符指针变量作形参和实参
#include<stdio.h>
int main()
{
void copy_string(char from[],char to[]);
char *a="I an a teacher";
char b[]="You are a programmer";
char *p=b;
printf("string a=%s\n string b=%s\n",a,b);
printf("copy string a to string b:\n");
copy_string(a,p);
printf("\n string a=%s\n string b=%s\n",a,b);
return 0;
}
void copy_string(char *from,char *to)
{
for(;*from!='\0';from++,to++)
{*to=*from;}
*to='\0';
}
总结:
(1)首先要准确地弄清楚指针的含义.指针就是地址,凡是出现“指针”的地方,都可以用
“地址”代替,例如,变量的指针就是变量的地址,指针变量就是地址变量。
要区别指针和指针变量。指针就是地址本身,例如2008是某一变量的地址,2008就
是变量的指针。而指针变量是用来存放地址的变量。
(2)什么叫指向?地址就意味着指向,因为通过地址能找到具有该地址的对象。对于指
针变量来说,把谁的地址存放在指针变量中,就说此指针变量指向谁。但应该注
意:并不是任何类型的数据都可以存放在同一个指针变量中的。例如:
int a,*p;
float b;
p=&a; //a是int类型,合法
p=&b; //b是float类型,类型不匹配
(3)指针运算
指针变量加(减)一个整数。
例如:p++,p- -,p+i,p-i,p-=i等均是指针变量加减一个整数。
将该指针变量的原值(地址)和它指向的变量所占用的存储单元的字节数相加(减)。
指针变量赋值
将一个变量地址赋给一个指针变量。例如:
p=&a; //将变量a的地址赋给p
p=&array; //将数组array的首元素地址赋给p
p=&array[i]; //将数组array的第i个元素的地址赋给p
p=max; //max为已定义的函数,将max的入口地址赋给p
p1=p2; //p1和p2是基类型相同指针变量,将p2的值赋给p1
使用指针有两大优势优势:
· 提高编程效率
· 在调用函数是当指针指向变量的值改变时,这些值能够为主调函数使用,即可以从函数
调用得到更多个可改变的值