小工具知识网

当前位置: 首页 > 行业知识 > C语言——指针

行业知识

C语言——指针

2026-10-23 10:50:26 来源:互联网转载

���针的优点:

  1. 使程序更简洁、紧凑、高效
  2. 有效的表达更复杂的数据结构
  3. 动态分配内存
  4. 得到多于一个数的函数返回值

1. 指针的基本用法

1.1 指针的概念

  • 内存地址:内存中每个字节单位都有一个编号(一般用十六进制表示)

  • 指针:指针就是内存地址

  • 指针变量:用于存放地址的变量就叫做指针变量

    指针变量画图展示:

    1.2 格式

    存储类型 数据类型 *指针变量名;

    int *p; //定义了一个指针变量p,指向的数据是int类型的。

    int a = 5;int *p = &a;char c='v';char *q=&c;printf("%p %p\n", p, &a);printf("%p %p\n",q,&c);printf("%d %d\n",a,*p);printf("%c %c\n",c,*q);

    访问指针所指向空间的内容用取内容运算符*

    那么p变量存放的就是a的地址,q变量存放的是c的地址。

    符号*可以访问地址里面的内容。

    指针与所指变量之间的关系如下图:

    int i=3;

    int *i_potinte=&i;

    2.3 指针操作符

    • &:取地址符:取变量的地址

    • *:取内容符:取地址里面存放的内容

      *&a=a;//*和&是互逆运算

      &*a//错误(因为运算符优先级)

      2.4 指针变量初始化和赋值

      指针变量使用前不仅要定义,还要初始化。未初始化的指针变量不能随便使用,不然可能会产生野指针。

      (1)将普通变量的地址赋值给指针变量

      #include int main(int argc, char const *argv[]){    int a=10;    int *p = &a;//定义的同时赋值    int *q=NULL;//可以初始化为空指针    int *p2;    p2=p;//先定义后赋值    printf("%d %d %d\n",a,*p,*p2);//打印a的值    printf("%p %p %p\n",&a,p,p2); //打印a的地址    *p=20;                        //同过指向a的指针改变a的值    printf("%d %d %d\n",a,*p,*p2);//打印a的值    printf("%p %p %p\n",&a,p,p2); //打印a的地址    return 0;}

      (2)将数组的首地址赋值给指针变量

      char s[10]="hello";char *p = s;int arr[5]={1,2,3,4,5};int *q=arr;printf("%c\n",*p);//hprintf("%d\n",*q);//1

      (3)将指针变量里面保存的地址赋值给另一个指针变量

          int a=10;    int *p=&a;    int *q=p;    printf("%d %d %d\n",a,*p,*q);    *q=20;//通过指针改变变量a的值    printf("%d %d %d\n",a,*p,*q);

      p和q都指向了变量a

      2. 指针运算

      2.1 算术运算- +

      对指针加减操作其实就是让指针向前向后移动

          char str[32]="hello";    char *p=str;    printf("%c\n",*p);    p++;    printf("%c\n",*p);    p--;    printf("%c\n",*p);

      int *p;p++;//移动4字节

      double *q;q++;//移动8字节

      p+n:访问高地址方向的第n个数据的地址,指针的指向不发生变化。

      p-n:访问低地址方向的第n个数据的地址,指针的指向不发生变化。

      偏移了多少字节=n*sizeof(数据类型)

      2.2 关系运算 > >= p1"); else printf("p2);

      练习:以下程序打印出来什么

      char s[32]="hello";char *p=s;p++;cchar y=(*--p)++;printf("%c",y);//h

      练习:以下程序打印什么结果

      int x[] = {10, 20, 30};int *px = x;printf("%d,", ++*px);//11printf("%d\n", *px); //11px = x;printf("%d,", (*px)++);//11printf("%d\n", *px);//12px = x+1;printf("%d,", *px++);//20printf("%d\n", *px);//30px = x+1;printf("%d,", *++px);//30printf("%d\n", *px);//30

      练习:下面程序段的运行结果是

      char a[ ]=”language” , *p ;

      p=a ;

      while (*p!=’u’) { printf(“%c”,*p-32); p++ ; }

      A)LANGUAGE B)language C)LANG D)langUAGE

      C

      3. 指针的大小和段错误

      3.1 指针的大小

      计算指针大小用:sizeof(指针变量名)

          int a=5;    short b=6;    char c='a';    int *p1=&a;    short *p2=&b;    char *p3=&c;    printf("%d %d %d\n",sizeof(p1),sizeof(p2),sizeof(p3));//4 4 4 4

      总结:

      1. 32位操作系统指针大小是4字节。64位操作系统,指针大小是8字节。

      2. 内存地址是固定的,但是变量的地址不是固定的。

      3. 指针类型根据指针指向的空间的数据类型来匹配

      练习:

      利用指针判断输入的字符串是否为回文

      #include #include int main(int argc, char const *argv[]){   char a[32]={};   char *p1,*p2;   int flag=1;   gets(a);   p1=a;   p2=a+strlen(a)-1;   while(p2>p1)   {       if(*p1!=*p2)            flag=0;       p1++;       p2--;   }    if(flag==0)        printf("no!\n");    else         printf("yes!\n");    return 0;}

      练习:编写一个程序实现功能:将字符串“Computer Science”赋值给一个字符数组,然后从第一个字母开始间隔的输出该字符串,用指针完成。结果:Cmue cec

      #include #include int main(int argc, char const *argv[]){    char string[32] = "Computer Science";    char *p = string;    while (*p != '

      3.2 使用指针时报段错误

      ') { printf("%c", *p); p += 2; } printf("\n"); return 0;}
          int a=10;    int *p=&a;    scanf("%d",p);    printf("%d\n",*p);

      段错误: Segmentation fault (core dumped)

      (1)野指针,没有规定指向的指针会在内存中乱指。

      野指针产生的原因,主要有两种:

      【1】指针变量没有初始化

      【2】指针被free之后,没有置NULL,会让人认为时合法指针。

      这两种情况都是没有给指针规定指向。

      例如:int *p;

      scanf(“%d”, p);

      printf(“%d\n”,*p);

      修改:

      #include #include int main(int argc, char const *argv[]){    char a[32]="123";    char *p=a;    int num=0;    while(*p != '

      4. 指针修饰

      ') { num = num*10+(*p-48); p++; } printf("num=%d\n",num); return 0;}

      (2)内存泄露,对非法空间进行赋值。

      练习1.将字符串转换成整型数字输出。用指针实现

      4.1 const 常量化

      (1)修饰普通变量

          const int a=10;    int const b=20;    int *p=&a,*q=&b;    printf("%d %d\n",a,b);//10 20    *p=1;    *q=2;    //a=1;//error: assignment of read-only variable ‘a’    //b=2;//error: assignment of read-only variable ‘b’    printf("%d %d\n",a,b);//1 2 

      (2) 修饰指针指向的内容

      const int a=10;

      int const b=10;

      此时a和b只读,不可以修改。但是可以通过指针修改。

      const int *p;int const *p;
      #include int main(int argc, char const *argv[]){    int a=10;    int b=20;    int const *p=&a;    const int *q=&b;    printf("%d %d\n",a,b);//10 20    //*p=1;//*p只读不可以被更改    //*q=2;//*q只读不可以被更改    p=q;    printf("%d %d\n",*p,*q);//20 20    return 0;}

      也就是修饰*p,此时指针指向的内容不能改变,但是指向可以改变。

      #include int main(int argc, char const *argv[]){    int a=10;    int *const p=&a;    printf("%d\n",*p);    //p=NULL;//error: assignment of read-only variable ‘p’    *p=20;    printf("%d\n",*p);    return 0;}

      4.2 void

      (3) 修饰指针指向

      int *const p;

      此时const修饰p,指针指向不能被更改,但是指向的内容可以被更改。

      int a=100;void *p=&a;int *q=(int *)p;printf("%d %d\n",*(int *)p,*q);

      4.3 大小端

      (1) 不允许修饰普通变量:void a;//错误

      (2) 可以修饰指针:void *p;

      此时p是一个任意类型的指针

      使用场景:函数参数或函数返回值。

      注意:通过void类型修饰的指针进行取内容时,需要进行强制转换。

      转换方式:(int *)p 为右值

      #include #include int main(int argc, char const *argv[]){    int a=0x12345678;    char *p=(char *)&a;    if(*p==0x78)        printf("LSB\n");    else if(*p==0x12)        printf("MSB\n");        return 0;}

      现用现转,或者转换之后赋值给另外一个变量然后应用另外一个变量。

      5. 二级指针

      在计算机进行超过1字节数据进行存储时,会出现存储数据顺序不同的情况即大小端存储

      • 大端:数据的低位存储在高地址位,数据的高位存储在低地址位,大端字节序称为MSB

      • 小端:据的低位存储在低地址位,数据的高位存储在高地址位,小端字节序称为LSB

        举例:存储数据:0x12345678, 假设起始地址是0x4000

        地址:0x4000 0x4001 0x4002 0x4003

        小端:0x78 0x56 0x34 0x12

        大端:0x12 0x34 0x56 0x78

        5.1 格式

        a的值
        • 一级指针:存放变量的地址

        • 二级指针:存放一级指针的地址

          a的地址

          存储类型 数据类型 **指针变量名;

          int a = 10;

          int *p = &a;

          int **q = &p;

          此时p指向了a,q指向了p也就是q里保存了p的地址。访问a的值,a的地址和p的地址:

          #include #include int main(int argc, char const *argv[]){    int a=10;    int *p=&a;    int **q=&p;    printf("%d %d %d\n",a,*p,**q);    printf("%p %p %p\n",&a,p,*q);    printf("%p %p\n",&p,q);    return 0;}
          10 10 100xbf9839b0 0xbf9839b0 0xbf9839b00xbf9839b4 0xbf9839b4
          p的地址a&a
          &p*pp
          q**q*q

          验证:

          6.指针和一维数组

          结果:

          6.1 用法

          #include int main(int argc, char const *argv[]){    int a[3]={1,2,3};    int *p=a;    printf("%p %p %p %p\n",a,p,&a[0],&p[0]);    printf("%p %p %p %p\n",a+1,p+1,&a[1],&p[1]);    printf("%d %d %d %d\n",a[0],p[0],*a,*p);    printf("%d %d %d %d\n",a[1],p[1],*(a+1),*(p+1));    return 0;}
          0xbfb27e90 0xbfb27e90 0xbfb27e90 0xbfb27e900xbfb27e94 0xbfb27e94 0xbfb27e94 0xbfb27e941 1 1 12 2 2 2

          int a[5]={1,2,3,4,5}; //a是数组名,也是数组首地址。

          int *p=a;

          (1)直接访问:

          (2)通过地址间接访问:

          访问数组元素a[i]的地址:

          • 直接访问:&a[i] 或 a+i

          • 间接访问:&p[i] 或 p+i

            访问数组元素a[i]的内容:

            • 直接访问:a[i] 或 *(a+i)

            • 间接访问:p[i] 或 *(p+i)

              #include #include int main(int argc, char const *argv[]){    char str[32]="";    char *p1=str,*p2=NULL;    int temp=0;    gets(str);    p2=p1+strlen(str)-1;    while (p2>p1)    {        temp=*p1;        *p1=*p2;        *p2=temp;        p1++;        p2--;    }    printf("%s\n",str);        return 0;}

              打印结果:

              11 11 2 11 3 3 11 4 6 4 11 5 10 10 5 11 6 15 20 15 6 1

              练习:用指针实现字符串“hello”的倒序打印。

              #include int main(){    int a[10][10], i, j;    /*负责对角线和每行第一列*/    for (i = 0; i 

              练习:打印杨辉三角形前十行

上一篇:Win10摄像头使用教程,轻松开启,留住精彩瞬间

下一篇:ftp服务器怎么下载软件?