C语言—指针

简介: 本文介绍了C语言指针的知识。


🎀 文章作者:二土电子
🐸 期待大家一起学习交流!


1 指针

1.1 指针的定义

指针是内存单元的地址,它可能是变量的地址、数组的地址,或者是函数的入口地址。存储地址的变量称为指针变量,简称为指针。定义指针的格式如下

int* p;
char* p;

在使用指针时,需要明确两个概念,指针对象和指针指向的对象。指针对象指的是明确命名的指针变量,也就是上面的p。指针指向的对象是另一个变量,用*p来表示。

上面定义指针时,没有对指针进行初始化。未初始化的指针变量的值是随机的。在使用指针时,如果没有对指针进行初始化,可能会导致程序运行时出现非法指针访问错误,从而使程序异常终止。因此,在定义指针时需要对指针初始化

如果在定义指针时,并不能确定指针变量的初始值。可以将指针定义成空指针。

int* p = NULL;

或者

int* p = 0;

有一种特殊的指针类型void,void类型可以与任意的数据类型匹配。void 指针在被使用之前,必须转换为明确的类型。

1.2 “&”和“*”

“&”是地址运算符,它的作用是获取变量的地址。“*”是间接运算符,它的作用是获取指针所指向的变量。可以通过一个简单的程序,直观地了解一下这两个运算符的作用

#include<stdio.h>
int main()
{
   
   
    int i = 0;
    int* p = &i;   // 获取i的地址

    *p = 10;   // 给i赋值

    printf("**************************\n");
    printf("i的值为:%d\n",i);
    printf("**************************\n");
    return 0;
}

输出内容为

**************************
i的值为:10
**************************

有一种特殊类型的指针void,void类型可以与任意的数据类型匹配。void 指针在被使用之前,必须转换为明确的类型

#include<stdio.h>

int main()
{
   
   
    int i = 0;
    void* p = &i;   // 获取i的地址

    // void 指针在被使用之前,必须转换为明确的类型
    *(int*)p = 10;   // 给i赋值

    printf("**************************\n");
    printf("i的值为:%d\n",i);
    printf("**************************\n");
    return 0;
}

1.3 指针与堆内存

堆内存能够被动态地分配和释放,在 C 程序中通过malloc(或 calloc、realloc) 和 fee 函数实现对内存的分配和释放。

malloc是动态内存分配函数,用于申请一块连续的指定大小的内存块区域,以void*类型返回分配的内存区域的首地址。如果内存分配失败,会返回NULL。malloc函数的输入值是要开辟的内存所占的字节数。在使用malloc函数时,需要声明malloc.h头文件。可以通过一个简单的程序来了解一下malloc函数的使用方法

#include <stdio.h>
#include <malloc.h>

int main()
{
   
   
    // 分配一个4字节内存,p指向首地址
    int* p = (int*)malloc(sizeof(int));

    // 分配一个8字节内存,c指向首地址
    char* c = (char*)malloc(8 * sizeof(char));

    *p = 10;   // 将10存储到第一个内存块
    strcpy(c,"20230712");   // 将一串字符串存储到第二块内存块

    printf("**************************\n");
    printf("第一块内存内容为:%d\n",*p);
    printf("第二块内存内容为:%s\n",c);
    printf("**************************\n");
    return 0;
}

输出结果为

**************************
第一块内存内容为:10
第二块内存内容为:20230712
**************************

因为内存资源是有限的,所以若申请的内存块不再需要就及时释放。如果程序中存在未被释放(由于丢失其地址在程序中也不能再访问) 的内存块,则称为内存泄漏。持续的内存泄漏会导致程序性能降低,其至崩溃。释放内存块使用的是free函数。使用后该指针变量一定要重新指向NULL,防止悬空指针(失效指针)出现,有效规避错误操作

    free (p);   // 释放第一块内存
    *p = 0;   // 将p重新设置为空指针

    free (c);   // 释放第二块内存
    *c = 0;   // 将c重新设置为空指针

1.4 指针运算

指针变量可以加上或者减去整数值,叫做指针的运算。指针运算会在利用指针访问数组元素时用到,下面会介绍。

#include <stdio.h>

int main()
{
   
   
    int* p = 0x20020;

    p = p + 1;

    printf ("p的地址为:%p",p);

    return 0;
}

输出结果为

p的地址为:0x20024

加1的意思是指向下一个地址。注意这里的加1实际是往后推了4字节的内容。具体往后推几个字节,取决于指针变量的类型

1.5 常量指针与指针常量

1.5.1 常量指针

指针指向的对象时常量,这个指针叫做常量指针

const int* p = 0;   // 定义一个常量指针

在定义时,const修饰p,而p是指针指向的对象。它可以等效定义为

int const* p = 0;   // 定义一个常量指针

常量指针由于指针指向的对象是常量,所以指针指向对象的值是不可以被改变的。但是指针变量本身的值可以改变。

1.5.2 指针常量

指针常量是指指针本身是一个常量,不能再指向其他对象。

int* const p = 0;   // 定义一个指针常量

由于指针常量中,指针本身是一个常量,所以指针的值不能被改变。但是指针指向对象的值可以被改变。

1.6 函数指针

在C语言中,可以将函数地址保存在函数指针变量中,然后用该指针间接调用函数。函数指针的定义方法是

函数的返回值类型(*指针名)(函数的参数列表类型)

看一个简单的例子

#include <stdio.h>

int add (int a,int b)
{
   
   
    return a + b;
}

int main()
{
   
   
    int i = 0;
    int (*p)(int,int) = &add;   // 定义函数指针

    i = p(2,3);

    printf ("i=%d",i);

    return 0;
}

输出结果为

i=5

在定义函数指针时。&函数名,是函数的起始地址

2 指针与数组

可以利用指针去访问数组。看一个简单的例子

#include <stdio.h>

int main()
{
   
   
    int temp = 0;   // 临时循环变量
    char a[10];
    char* p = &a[0];   // 定义一个指针,指向数组起始地址

    // 利用指针给数组成员赋值
    for (temp = 0;temp < 10;temp ++)
    {
   
   
        *(p + temp) = temp;
    }

    // 利用指针读取数组成员的值
    for (temp = 0;temp < 10;temp ++)
    {
   
   
        printf ("a[%d]=%d\n",temp,*(p + temp));
    }

    return 0;
}

输出结果为

a[0]=0
a[1]=1
a[2]=2
a[3]=3
a[4]=4
a[5]=5
a[6]=6
a[7]=7
a[8]=8
a[9]=9

3 指针与函数

指针可以作为函数的输入参数或者返回值。

这里看一个常见的函数,利用指针交换两个参数的值

#include <stdio.h>

void swap (int* x,int* y);

int main()
{
   
   
    int i = 10;
    int j = 100;

    swap (&i,&j);

    printf ("i=%d,j=%d",i,j);

    return 0;
}

void swap (int* x,int* y)
{
   
   
    int temp = *x;
    *x = *y;
    *y = temp;
}

输出结果为

i=100,j=10

其中指针x和y是函数swap的输入参数。

指针也可以作为函数返回值,但是把指针作为返回值不是很推荐

4 指针与链表

4.1 链表

什么是链表?链表是一种动态地进行存储分配的数据结构。链表中的每一个元素称为一个结点。每个结点都应该包含两个部分,分别是用户实际需要的数据和下一个结点的地址。链表有一个头指针变量,这个变量存放一个地址,这个地址指向一个元素。链表的最后一个元素称为表尾,它的地址部分存放NULL。

链表中各个元素的地址可以是不连续的。要找某一个元素,必须先找到该元素的上一个元素,根据上一个元素提供的地址来找到下一个元素。如果不知道头指针,那么整个链表都无法访问。链表的基本结构如下

92bed97f687c350b45f5a674f6ebcac1_29a8cb3cfa2b41beacac48a1ff7e55d8.png

4.2 链表的建立与输出

这里通过一个例子来展示一下链表的建立与输出。

#include<stdio.h>

struct student
{
   
   
    char* name;
    int age;
    char* number;
    struct student* next;   // 下一个结点的地址
}student;

int main()
{
   
   
    struct student a,b,c;
    struct student* head;   // 头指针
    struct student* p;   // 用来访问链表的指针

    // 结构体成员赋值
    a.name = "ertu";
    a.age = 23;
    a.number = "001";

    b.name = "yingting";
    b.age = 18;
    b.number = "002";

    c.name = "yitong";
    c.age = 14;
    c.number = "003";

    head = &a;   // 头指针
    a.next = &b;
    b.next = &c;
    c.next = NULL;   // 表尾

    p = head;

    // 输出链表内容
    while (p != NULL)
    {
   
   
        printf("**************************\n");
        printf("Name:%s,Age:%d,Number:%s\n",p->name,p->age,p->number);
        printf("**************************\n");

        p = p->next;
    }

    return 0;
}

输出结果为

**************************
Name:ertu,Age:23,Number:001
**************************
**************************
Name:yingting,Age:18,Number:002
**************************
**************************
Name:yitong,Age:14,Number:003
**************************
相关文章
|
1月前
|
存储 C语言
【C语言篇】深入理解指针3(附转移表源码)
【C语言篇】深入理解指针3(附转移表源码)
36 1
|
22天前
|
C语言
【c语言】指针就该这么学(1)
本文详细介绍了C语言中的指针概念及其基本操作。首先通过生活中的例子解释了指针的概念,即内存地址。接着,文章逐步讲解了指针变量的定义、取地址操作符`&`、解引用操作符`*`、指针变量的大小以及不同类型的指针变量的意义。此外,还介绍了`const`修饰符在指针中的应用,指针的运算(包括指针加减整数、指针相减和指针的大小比较),以及野指针的概念和如何规避野指针。最后,通过具体的代码示例帮助读者更好地理解和掌握指针的使用方法。
44 0
|
21天前
|
C语言
【c语言】指针就该这么学(3)
本文介绍了C语言中的函数指针、typedef关键字及函数指针数组的概念与应用。首先讲解了函数指针的创建与使用,接着通过typedef简化复杂类型定义,最后探讨了函数指针数组及其在转移表中的应用,通过实例展示了如何利用这些特性实现更简洁高效的代码。
15 2
|
22天前
|
C语言
如何避免 C 语言中的野指针问题?
在C语言中,野指针是指向未知内存地址的指针,可能引发程序崩溃或数据损坏。避免野指针的方法包括:初始化指针为NULL、使用完毕后将指针置为NULL、检查指针是否为空以及合理管理动态分配的内存。
|
22天前
|
C语言
C语言:哪些情况下会出现野指针
C语言中,野指针是指指向未知地址的指针,通常由以下情况产生:1) 指针被声明但未初始化;2) 指针指向的内存已被释放或重新分配;3) 指针指向局部变量,而该变量已超出作用域。使用野指针可能导致程序崩溃或不可预测的行为。
|
28天前
|
存储 C语言
C语言32位或64位平台下指针的大小
在32位平台上,C语言中指针的大小通常为4字节;而在64位平台上,指针的大小通常为8字节。这反映了不同平台对内存地址空间的不同处理方式。
|
27天前
|
存储 算法 C语言
C语言:什么是指针数组,它有什么用
指针数组是C语言中一种特殊的数据结构,每个元素都是一个指针。它用于存储多个内存地址,方便对多个变量或数组进行操作,常用于字符串处理、动态内存分配等场景。
|
28天前
|
存储 C语言
C语言指针与指针变量的区别指针
指针是C语言中的重要概念,用于存储内存地址。指针变量是一种特殊的变量,用于存放其他变量的内存地址,通过指针可以间接访问和修改该变量的值。指针与指针变量的主要区别在于:指针是一个泛指的概念,而指针变量是具体的实现形式。
|
28天前
|
C语言
C语言指针(3)
C语言指针(3)
11 1
|
28天前
|
C语言
C语言指针(2)
C语言指针(2)
13 1