C语言学习,这一篇就够了!(四)-- 指针

举报
阿童木 发表于 2021/08/18 07:32:07 2021/08/18
【摘要】 5. 指针每一个变量都有一个内存位置,可使用 & 取地址符来访问它的内存地址,它表示了在内存中的一个地址。🍟指针也就是内存地址,指针变量是用来存放内存地址的变量。就像其他变量或常量一样,必须在使用指针存储其他变量地址之前,对其进行声明。格式为:类型 *变量名int *ip; /* 一个整型的指针 */double *dp; /* 一个 double 型的指针 */flo...

5. 指针

每一个变量都有一个内存位置,可使用 & 取地址符来访问它的内存地址,它表示了在内存中的一个地址。🍟

指针也就是内存地址,指针变量是用来存放内存地址的变量。就像其他变量或常量一样,必须在使用指针存储其他变量地址之前,对其进行声明。

格式为:类型 *变量名

int    *ip;    /* 一个整型的指针 */
double *dp;    /* 一个 double 型的指针 */
float  *fp;    /* 一个浮点型的指针 */
char   *ch;    /* 一个字符型的指针 */

不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。

形象的说:一个房间的门口挂了一个房间号1304,这个1304就是房间的地址,或者说1304指向这个房间。因此把地址形象化的称为指针。

指针变量可指向任意一种数据类型,但不管指向的数据占用多少字节,一个指针变量占用四个字节。

5.1 指针变量

存放地址的变量是指针变量,它用来指向另一个对象

注意:在定义指针变量时,必须确定指针类型。例如:int变量的指针需要用int类型指针来存储。

区分指针变量和指针,指针是一个地址,而指针变量是存放地址的变量

5.1.1 使用指针变量

通过指针变量访问整型变量

#include <stdio.h>
int main()
{
    int a = 100;
    int *pointer;
    pointer = &a;
    printf("*pointer的值是%d", *pointer);
    return 0;
}

先定义一个整型变量,再定义一个指针变量,指向这个整型变量,通过访问指针变量可以找到它所指向的变量,从而得到变量的值

5.1.2 定义指针变量

定义指针变量需要在变量名前面加星号*,例如

int *try;

*表示这是一个指针变量,int表示该指针变量所指向的数据的数据类型是int类型

int a = 100;
int *p = &a;

在定义指针变量p时同时对它进行初始化,将变量a的地址赋予它,此时p就指向了a

注意:

  1. 指针变量p需要接收的是一个地址,因此需要使用&取地址符,来获取a的地址
  2. 定义指针变量时必须带*号,给指针变量赋值时不能带*
  3. 指针变量p的类型是int *而不是int噢,它们是完全不同的,考试避坑噢~

5.1.3 引用指针变量

  1. 给指针变量赋值
p = &a; //a的地址赋值给指针变量p

指针变量 p 的值是变量 a 的地址,p 指向 a

  1. 引用指针变量指向的变量
p = &c;
printf("%d",*p);

printf("%d",*p);的意思是:一整数形式输出指针变量 p 指向的变量的值

*p = 1;

表示将整数1赋值给 p 所指向的变量,即c = 1

  1. 引用指针变量的值
printf("%o",p);

作用是以八进制形式输出指针变量 p 的值,如果 p 指向了 a ,输出的就是 a 的地址

*和&:这两个符号的作用是相对的,可以理解为&是取变量的内存地址,*号是取地址上的变量值,也就是解引的作用

int a;
*&a = a;

*&a可以理解为*(&a)&a表示取变量 a 的地址,*(&a)表示取这个地址上的数据

5.2 指针变量作为函数参数

在前面的函数部分中,我们有说到

“传数值,形参的变化不会改变实参的变化;传地址,形参的变化就有可能改变实参所对应的值”

指针变量作为函数参数就是传地址的情况,这能帮助我们解决一些问题。一个典型的例子就是交换两个变量的值

当我们想要交换两个变量时,我们可以声明一个swap交换函数,交换两个变量的值,但是,采用常规的值传递的方式是行不通的

#include <stdio.h>
void swap(int a, int b){
    int temp;  
    temp = a;
    a = b;
    b = temp;
}
int main(){
    int a = 1, b = 2;
    swap(a, b);
    printf("a = %d, b = %d", a, b);
    return 0;
}

因为函数内部的a,b都是局部变量,它们占用着不同的内存,改变swap函数中的a,b值,不会影响到main函数中a,b的值


采用用指针变量作为函数参数,就可以解决这个问题,因为参数的传递是内存地址,外部函数,直接通过修改内存地址上的值,来完成操作

#include <stdio.h>
void swap(int *p1, int *p2){
    int temp; 
    temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}
int main(){
    int a = 1, b = 2;
    swap(&a, &b);
    printf("a = %d, b = %d", a, b);
    return 0;
}

5.3 通过数组引用指针

5.3.1 数组元素的指针

🎉**所谓数组元素的指针就是数组元素的地址**

可以用一个指针变量指向一个数组元素,例如

int a[3] = {1, 2, 3};
int *p;
p = &a[0]

引用数组元素可以采用下标法a[1],也可以采用指针法,指针法占用内存更少,运行速度更快

在数组部分,我们知道数组名称代表了首元素的地址,因此我们可以直接写p = a,来指向数组的第一个元素

5.3.2 在引用数组元素时的运算

在指针已经指向一个数组元素的情况下,可以进行下列运算

p + 1:指向同一数组中的下一个元素

p - 1:指向同一数组的上一个元素

注意p + 1不是简单的数值上的加一,而是加上一个数组元素所占的字节数,如float类型数组一个元素占4个字节,p的值就加4,也就指向了下一个元素

如果p的初值指向的是数组的第一个元素a[0]那么可想而知p + i就能访问到数组元素a[i]的地址,例如p + 9的值是&a[9],同样的我们获取到了了数组元素的地址,就可以采用*号来得到它的值,如*(p + i) = a[i]

5.3.3 练习题

🎉通过指针变量输出整型数组a的10个元素

#include <stdio.h>
int main()
{
    int *p, i, a[10];
    p = a; //a的地址
    printf("请输入10个整数:\n");
    for (i = 0; i < 10; i++)
    {
        scanf("%d", p++);
    }
    p = a;//由于指针p在遍历的过程改变了,因此要重新赋值
    for (i = 0; i < 10; i++, p++)
    {
        printf("%d ", *p);
    }
    return 0;
}

在遍历时,采用了p++,在每一次遍历结束后,将指针p指向数组的下一位

5.4 指针数组和数组指针

指针数组:它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身决定。也叫做存放指针的数组

数组指针:它是一个指针,它指向一个数组。在32 位系统下永远是占4 个字节,也叫做指向数组的指针

5.5 通过指针引用字符串

在前面我们也有提到过“c语言中没有字符串变量”,但是可以通过字符数组和字符指针的方式存储字符串

我们先从一个简单的题目入手

通过字符指针变量输出一个字符串

#include <stdio.h>
int main()
{
    //定义一个字符指针来存储字符串
    char *string = "i am ljc";
    // 输出
    printf("%s", string);
    return 0;
}

在上面的代码中成功的输出了i am ljc,我们可以知道,在输出string时,字符指针最开始指在了字符串的第一个字符,又因为字符串在内存中占据的是连续的内存空间,在输出控制符%s下,系统会自动的输出字符串的第一个字符,然后让字符指针指向下一个字符,直至遇到\0结束。

字符指针变量和字符数组的比较

  1. 字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址
  2. 赋值方式不同,可以对字符指针变量赋值,而不能对数组名赋值
  3. 存储单元不同,编译时字符数组分配若干存储单元,以存放各元素的值,而对字符指针变量,只占4各字节(不同编译器可能不同)
  4. 指针变量的值是可以改变的,而字符数组名代表一个固定的值,不能改变

5.6 指针作为函数返回值

当函数的返回值是一个指针时,把这个函数称为指针函数

#include <stdio.h>
#include <string.h>
char *longStr(char *str1, char *str2){
    if(strlen(str1) >= strlen(str2)){
        return str1;
    }else{
        return str2;
    }
}

上面的代码定义了一个返回长度较长字符串的函数

在使用指针函数时要注意,函数运行结束后会销毁在它内部定义的所有局部数据,函数返回的指针不要指向这些数据

5.7 练习题

🎋**第一题**

有定义:int x,*p;,能使指针变量p指向变量x的语句是(  )。

A) *p=&x;  B) p=&x; C) *p=x;  D) p=*&x;

==答案:B==

🎄**第二题**

若有语句int *p, a=10; p=&a; 下面均代表地址的一组选项是()。

A. a, p, *&a B. &*a, &a, *p

C.*&p, *p,&a D.&a, &*p, p

==答案:D==

🎍**第三题**

若已定义char s[10];则在下面表达式中不表示s[1]地址的是()。

A. s+1 B. s++ C. &s[0]+1 D. &s[1]

==答案:B==

🧶**第四题**

若定义:int a=511, *b=&a;则printf("%d\n", *b);的输出结果为:

A. 无确定值 B. a的地址 C. 512 D. 511

==答案:D==

🔋**第五题**

下面程序中输出几个*

A. 9 B. 5 C. 6 D.7

#include <stdio.h>
int main()
{
    char *s = "\ta\018bc";
    for (; *s != '\0'; s++)
    {
        printf("*");
    }
}

==答案:C== \0是转义字符表示后面是个8进制数


定 义 含 义
int *p; p 可以指向 int 类型的数据
int **p; p 为二级指针,指向 int *类型的数据
int *p[n]; p 为指针数组。[ ] 的优先级高于 *,所以应该理解为 int *(p[n]);
int (*p)[n]; p 为二维数组指针
int *p(); p 是一个函数,它的返回值类型为 int *
int (*p)(); p 是一个函数指针,指向原型为 int function() 的函数
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。