指针_C语言快速入门与计算机二级备考

指针概念

  • 指针就是保存地址的变量

  • int *p = &i; * 表示这是一个指针,p指向i,p这个变量保存了i这个变量的地址

    注意:int* p,q p是指针,q只是普通变量;想让两者都是指针:int *p,*q

  • 普通变量的值是实际值,指针变量的值是具有实际值的变量的地址

    使用一个指针变量,必须在指向另一个变量之后 再使用指针

指针运算

地址与变量

  • &与*这两个运算符相互起反作用
& 取地址符
  • 它的作用是获得变量的地址,操作数必须是变量

    无法对没有地址的变量取地址,必须是一个明确的变量

  • 在输出时 %p的占位符表示地址 输出的数带有0x前缀

  • 地址的大小是否与int相同取决于编译器,所以输出地址时不能直接用整数形式

  • 对于一个数组:&a=a=a[0],三者地址相同

    相邻单元的地址间的差距是4个字

* 访问指针所表示地址的变量
  • *是一个单目运算符(区别于乘的运算符),用以访问指针所表示地址上的变量

    得到的变量可作左值也可作右值(左值并非变量,而是可以接收值的值,是运算的结果)

  • 例如:int k = *p

指针与整数运算

对指针加减的含义
  • 指针+1运算,在其地址上+数据类型的一个sizeof( )

    实际上使得指针指向了下一个单元

    减即为指向上一个单元

  • 指向同一批连续分配的空间时,指针运算才有意义

  • char ac[]={……} char *p=ac 时, *(p+n) = ac[n]

  • 需要注意指针本身是分频的内存地址值,不能用整数赋值指针变量作为地址值

  • 指针相减

    两个指针相减,结果是 两个指针指向的地址的差/sizeof(当前的数据类型)

    这样的运算告诉你这两个地址之间有几个这样类型的单元

  • 指针递增

    *p++ 取出p所指的数据,并且把p移到下一位

    ++的优先级比*更高

指针比较

  • 指针也可使用关系运算符 <,<=,==,>=,>,!= 比较它们在内存中的地址
  • 数组中的单元的地址肯定是线性递增的

指针的类型

  • 无论指向什么类型,指针本身的大小是一样的(都是地址)

  • 指向不同类型的指针是不能直接互相赋值的

  • 特殊的指针

    特殊的:void* 表示不知道指向什么的指针 计算时同char*(但不相通)

    指针可以指向函数入口:有函数int fun(参数表);可用函数指针int(*f)(参数表)调用函数

    赋值为NULL的指针称空指针,其作用为操作系统保留,不能用于访问数据

  • 指针类型转换

    int *p =&i; void *q = (void*)p

    这不会改变p所指的变量类型,而是在之后用q的不同的眼光通过p看它所指的变量


指针应用

作为参数使用

  • 向函数传入较大的数据时,用指针作参数,例如传入数组,同时在传入后通过指针对数组作操作

  • 例如:void f(int *p);

    在被调用时得到了某个变量的地址:int i=0; f(&i);

  • 在函数里可以通过这个指针访问外面的变量

    在不同的函数中,原本只能传递值给函数,借由指针我们能够获得外面变量的地址,从而获得访问外部函数的能力

    但是指针变量本身作为函数参数,也要遵守形参实参数据单向传递的规则,调用函数不能改变实际参数指针变量的值,通过函数不能改变指针所指

  • 例如在函数本地变量章节的无法使用的swap函数可通过指针实现:

    void swap(int *a, int *b)
    {
    	int temp = *a;
    	*a = *b;
    	*b = temp;
    }
    int main()
    {
    	int a = 10;
    	int b = 2;
    	swap(&a, &b);//交上a与b的地址
    	printf("a=%d,b=%d", a, b);
    	return 0;
    }
    
  • 函数要返回多个值,某些值只能通过指针返回

    传入的参数实际上是需要保存带回的结果的变量

返回结果

  • 返回不止一个结果,或是需要用函数来修改不止一个变量,也会用到指针

  • 例如:

    函数自身的返回值用于返回运算的状态,运算结果用指针返回

    运算可能出错,需要另一种途径表达错误,一般让函数返回一个特殊的,不属于有效范围内的值表示出错,比如-1或0


数组与指针

数组和指针的关系

  • 函数参数表中的数组实际上是一个指针

  • 数组作函数参数

    这两种函数原型的参数等价

    int sum(int *ar,int n)=int sum(int ar[],int n)

    告知了传入的是数组,并用另一个参数n传入数组下标

  • 数组变量实际上是特殊的指针

    例如:int a[10]; int*p=a; 因为数组变量本身就表达地址,所以无需再用&取地址

    a的地址是数组的首个单元,不能用指针指向整个数组

    a==&a[0]; 数组的单元表达的是变量,需要用&取地址

    例如:scanf("%d",&a[2]);输入一个数赋给数组a的第三个单元的地址

两者的运算

  • 数组的[ ]运算符也可用于指针,将指针所指的部分当作只有一个元素的数组来处理

    例如:指针p指向一个值为2的变量的地址,p[0]相当于*p=2

  • 指针的*运算符也可用于数组

    例如:数组a包括100,2,4三个数,这时*a相当于a[0]=100

  • 数组变量是一个const的指针,所以不能被赋值改变

    例如:int *b 相当于 int *const b

指针数组

  • int *ptr[10]表示一个指针数组,其有10个元素,每个元素都是指向int的指针,p[0]表示某一个地址,*p[0]表示这个地址存放的数

  • int(*ptr)[10]则是一个指向一个含10个int元素的一维数组的指针,(*ptr)[0]将会得到这个数组的第一个元素

    对于二维数组,可以使用这种指针对每一行进行操作,例如:

    int arr[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};  
    int (*p)[4] = arr; // p 现在指向 arr 的第一行  
    
    printf("%d\n", (*p)[0]); // 输出 1  
    printf("%d\n", p[1][2]); // 输出 7,因为 p[1] 是指向 arr[1] 的指针
    

指针与const

  • 通过const在*的前后判断const的是所指还是指针

    *前const后:指针是const,int *const p=&i

    const前*后:所指是const,const int* p=&iint const* p=&i意义一致

  • 指针是const
    • 如果一个指针是const,那么它一旦得到了某个变量的地址,就不能再指向其它变量

    • 但是,想更改q的所指,比如q++这样的操作是不行的

    • 例如:

      int* const q =&i;这之后*q=24是可以的,因为q所指向的i并不是const

      但是,不能更改q的所指,比如q++这样的操作是不行的

  • 所指是const
    • 表示不能通过这个指针去修改所指的变量(但那个变量并不会成为const)

    • 例如:

      const int *p =&i;这之后可以让i=26,也可以改变p的所指,让*p=&j

      但是不可以让*p=24,即不能通过p来改变它所指的i

posted on   无术师  阅读(4)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了

统计

点击右上角即可分享
微信分享提示