C语言—指针

2023-11-19

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。

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

链表的基本结构

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
**************************
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言—指针 的相关文章

随机推荐

  • “条件递进式编程”技巧两例

    什么是 条件递进式编程 呵呵 这是我自己起的名字 所谓条件递进式编程 就是指需要一系列相关函数组合执行的情况下 后续函数执行的必要性由前面所有函数执行是否成功来决定 比如说 有一系列函数如下DoSomething1 DoSomething2
  • 端到端的图像压缩------《End-to-end optimized image compression》笔记

    End to end optimized image compression 简介 内容 整体算法结构以及流程如下 前向传播 变换优化问题 变分推导问题 实验结果 结论 论文地址 https arxiv org abs 1611 01704
  • 获取map中第一个key值

    获取map中第一个key值 param map 数据源 return public static String getKeyOrNull Map
  • SqliLabs Less26-26a

    第二十六关 GET类型基于你所有的空格和言论都是属于我的错误 1 判断注入点 根据提示 sql语句应该存在过滤 观察源代码发现存在or and 空格 斜杠过滤 绕过方法 Or and 采取双写绕过 注释过滤 采取and 1闭合语句绕过 空格
  • 获取url内的参数数据

    例如我们的页面 是含有参数的 类似于 www baidu com userdata 百度用户 我们想获得 url内的userdata的数据值 那么就需要 使用下方这个正则判断方式来进行计算 window location href 这个可以
  • SSM 基础面试题

    什么是 MyBatis 参考答案 1 MyBatis 是一个半自动 ORM 对象关系映射 框架 它内部封装了 JDBC 开发时只需要关注 SQL 语句本身 不需要花费精力去处理加载驱动 创建连接 创建 statement 等繁杂的过程 程序
  • VMware 中的 Ubuntu 虚拟机看不到共享文件夹怎么办?

    初学Linux 在VMWare 上装了Ubuntu14 04 主机端和虚拟机相互间的访问是必不可少的 途径有许多 其中vmware tool提供的共享文件夹方式简单又方便 然而 有时却莫名其妙的 在Ubuntu上看不到共享文件夹了 网上查了
  • 【vue3+elementplus】动态设置二次封装的el-form组件中的v-model绑定的变量名

    众所周知 在form表单中 el select el input等需要使用v model绑定变量 这个变量就是当前选择 输入的内容 一般会取ruleForm作为入参
  • java对象赋值给另一个对象_java注解实现对象的属性赋值,从此少写代码,快乐生活...

    各位志同道合的朋友们大家好 我是一个一直在一线互联网踩坑十余年的编码爱好者 现在将我们的各种经验以及架构实战分享出来 如果大家喜欢 就关注我 一起将技术学深学透 我会每一篇分享结束都会预告下一专题 我们平时在做一些业务时 从前台获取的数据用
  • 自定义模块导入错误

    当在python2 7 导入自定义模块 发生Importerror No module named xxx时 可将模块所在路径拷贝到E xxx python2 7 Lib site packages下 再进行导入则可解决问题 经过多方的摸索
  • MobaXterm出现X11-forwarding : ✘ (disabled or not supported by server)及conda: command not found等问题

    x11 forwarding disabled解决办法 3L csdn的博客 CSDN博客 如何安装X11 xorg https www cnblogs com yun qi p 16201843 html如何解决在Ubuntu中使用x11
  • 机器学习之线性回归——OLS,岭回归,Lasso回归

    机器学习之线性回归 线性回归 最小二乘法 OLS 岭回归 Ridge Regression Lasso回归 OLS 岭回归 Lasso回归之间对比 线性回归 什么是线性回归呢 其实线性回归是统计学中的 线性回归 Linear Regress
  • java 中的指针_Java中的指针

    java 中的指针 Java中有指针吗 简短的答案是 不 没有 这对于许多开发人员来说似乎是显而易见的 但是 为什么对其他人却不那么明显呢 http stackoverflow com questions 1750106 how can i
  • STM32实现HID键盘

    上面是我的微信和QQ群 欢迎新朋友的加入 这个帖子不是技术贴 是成品分享贴 电路设计 实物图 软件设计 功能说明 1 固件通过虚拟U盘升级 2 自定义按键功能 全键盘 3 七彩灯颜色设置 4 多媒体按键功能 5 支持按键双击和单击操作 6
  • c语言药房管理系统

    include
  • VisualStudio代码片段管理

    文章目录 前言 1 查看代码片段 2 插入代码片段方式 3 使用扩展创建代码片段 3 1 安装VS2019的扩展 3 2 使用扩展创建代码片段 4 不知为何 VS2022我安装一直有问题 扩展安装成功 但是新建文件没有 Snippet De
  • Unity 运行FixedUpdate()无响应

    问题 最近在学习unity时 根据 史上最全Unity3D教程 哔哩哔哩 bilibili 在Visual Studio中编写如下代码时 Unity的Console面板并没有输出预期的信息 即按每个固定帧速率的帧调用FixedUpdate
  • Matlab导出动态链接库dll

    1 新建 m文件 内容 function c Add a b c a b end 保存为 Add m 2 命令行输入 gt gt mex setup MEX configured to use Microsoft Visual C 2013
  • 各种注释总结

    jsp注释 html注释
  • C语言—指针

    文章目录 1 指针 1 1 指针的定义 1 2 和 1 3 指针与堆内存 1 4 指针运算 1 5 常量指针与指针常量 1 5 1 常量指针 1 5 2 指针常量 1 6 函数指针 2 指针与数组 3 指针与函数 4 指针与链表 4 1 链