C指针笔记

上来先说一下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;)

  在定义指针变量时要注意,指针变量前面的“*”表示该变量的类型为指针型变量.指针  变量名是p1p2,而不是*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+ia+i就是数组元素a[i]的地址,或者说,他们指向a数组

   序号为i的元素,见下图,这里注意的是a代表数组首元素的地址,a+1也是地址,

   它的计算方法同p+1,即它的实际地址为a+1*d。例如,p+9a+9的值是&a[9],

   指向a[9]

 3*p+i)和*(a+i)p+ia+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的值,然

     后使p1.后者是先使p1,再取*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+ip-ip-=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

 

使用指针有两大优势优势:

· 提高编程效率

· 在调用函数是当指针指向变量的值改变时,这些值能够为主调函数使用,即可以从函数

   调用得到更多个可改变的值

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值