C语言指针--一级指针
文章目录
前言
C语言有一个最重要的知识,是很多小白容易卡住并放弃的一个知识,并且是衡量一个C/C++程序员是否优秀的指标,那就是指针。
指针是C语言的核心,大家需要好好的学习。
本章内容是带领大家走进指针这个类型,希望大家学习后有很好的收获。
一、什么是指针
在学习C语言前大家都知道一个概念,就是低级语言和高级语言的区别,而C语言是属于高级语言,但又有低级语言的特点,那就是可以直接操作计算机底层,那C语言怎么可以操作底层的数据呢?就是靠C语言中的指针类型来进行操作。
而我们说的指针其实是属于C语言中的一个类型,和之前学习的类型一样,但只不过指针比较特殊,它是用来存放地址的一个类型。
比如前面学习的类型
int 变量;
float 变量;
double 变量;
char 变量;
int
就是存放整型的数据, float
和 double
存放浮点型的数据,char
存放的就是字符数据,每一个数据都能存放特定的内容。
指针类型也能存放一个具体的类型,那就是 地址。
通过操作地址来实行对底层的操作。
二、一级指针的使用
在学习一个东西时,最重要的是知道如何使用和创建,在使用中学习,所以先对指针的创建进行一下了解。
1.一级指针的创建
在上面说过,指针是属于一种特殊的数据类型,所以创建的时候和数据类型的创建一样,特殊点就在于指针也是分类型的,有整型指针、浮点数指针、字符型指针等等==(还有一些高级指针操作,等后面高级指针再说)==
也就是说现在的数据类型都可以创建为指针类型。
比如说最常见的 int
型的数据,它的指针的创建就是
int* 变量名;
float
类型的指针
float* 变量名;
而上面的 int*
和 float*
就是指针类型,分别表示整型指针和浮点数指针。
通过上面的创建可以推出以下的结论:
指针的创建:类型* 变量名;
C语言中的所有数据类型都有相应的指针类型
在创建指针类型时记得加上 *
2.指针的赋值
现在学会了创建指针类型,那如何对指针进行赋值就是这一小节需要学习的任务。
在前面对变量进行赋值时,使用的是下面的语句
类型 变量名 = 数值;
通过上面的语句可以对基础类型进行赋值,那对指针类型也采用上面的方法进行赋值可以吗?
可以想想,指针存储的是地址,该怎么给它地址,换句话来说,你怎么知道一个值的地址来给指针,显然没办法使用上面的方法进行赋值,因为上面给变量的都是具体类型的值,而给指针是需要地址,而不是 1234 这样的数。
所以指针的赋值方式是如下的
类型* 变量名 = &变量;
切记一定是变量名,而不是具体的值,如果使用具体的值会报错,下面演示一下。
用一个 int
型的指针来存放一个 int
型的变量
int a = 10;
int* pa = &a;
在电脑上跑一下程序
可以看到编译是没有任何问题的,如果使用具体的值会怎么样。
还是一样的,但我直接 &10
看看会发生什么
看到了吧, &
后必须是一个变量而不是一个数值,这样会报错的。
3.&是什么
可能会有很多人不知道 &
是什么东西,其实这个符号在使用输入语句时用到过,只不过没有细讲,这里说一下 &
到底是干嘛的。
&
其实是取址符,取它后面变量的地址的,比如上面2-1的代码
int* pa = &a;
的意思是将 a
变量的地址取出来然后赋值给指针变量 pa
。
大家记住即可。
4.一维指针的使用
4.1 变量
和 *变量
在前面数据类型 + *
就变成了指针类型,后面跟着的变量名是用来存储地址的。
所以直接使用 变量
得到的是地址,而 *变量
得到的是地址对应的值。
4.2 输出指针变量内容
先通过指针类型来获得地址处对应的值,代码如下
int a = 10;
int* pa = &a;
printf("%d\n", *pa);
从4.1知道,指针变量名对应的是地址,而*变量名得到的是对应的值,运行一下该代码看看是不是
发现真的输出了对应的值,那如果输出 pa
会变成什么结果呢
发现这个输出的是一个负数,我们看不懂,其实这个地方输出的是它存储的地址,只不过是将十六进制翻译成了10进制。
如果想看它里面存放的地址,可以将转义符 %d
变成 %p
,这样就可以知道里面存放的地址了
4.3 改变存储内容
先看一个例子:交换内容
在没学指针和函数之前,代码是写成这样的
#include <stdio.h>
int main(){
int a = 5, b = 6, temp;
temp = a;
a = b;
b = temp;
printf("%d %d\n", a, b);
return 0;
}
在学了函数后写的代码为:
#include <stdio.h>
void swap(int a, int b){
int temp;
temp = a;
a = b;
b = temp;
printf("%d %d\n", a, b);
}
int main(){
int a = 5, b = 6;
swap(a, b);
return 0;
}
但这个在函数运行结束后就被释放,不是真正的交换。
而现在在学指针,就可以使用指针的方式来写
指针的写法
#include <stdio.h>
void swap(int* a, int* b){
int temp;
temp = *a;
*a = *b;
*b = temp;
}
int main(){
int a = 5, b = 6;
swap(&a, &b);
printf("%d %d\n", a, b);
return 0;
}
使用指针的写法就可以完成数据的真正交换,执行一下程序
可以看到完成了交换,那为什么会这样呢?
用图的方式给大家解释一下,当把地址传入函数后,在函数 swap
中会有下面的形式
a下是存放着地址,b下也是存放地址,然后运行下一个代码 int temp = *a
在内存中创建了一个空间给 temp
用来存放指针a对应的值,也就是5
再进行下一步
将指针a地址对应的空间中的值改变成b地址对应的空间中的值
然后再对b指针对应的值进行一下修改
该函数只是对变量的地址进行操作,函数释放后只是把在函数中创建的指针a和b释放了,但地址还是存在的,所以在交换完后输出该地址中存放的元素就是交换后的元素。
三、野指针
从上面的介绍,大家是不是对指针有很大的喜爱,觉得指针的使用很好,但有没有思考过一个问题,为什么现在的编程语言没有指针这个知识了?
因为指针这个东西是把双刃剑,用得好就万事大吉,但用不好你根本就找不到你的程序到底错哪了。
导致这个原因的很大一个因素就是野指针。
1.野指针的危害
在前面学数据类型的时候,创建一个变量
int a;
如果没有进行赋值,它里面的值不可能永远是不可预知的是一个随机值,大家不信的话可以去调试一下。
那指针类型也是一样的,如果你只创建了指针变量,但没有给它赋值,它会产生一个随机值,指向内存中的未知空间。
而C语言可以直接操作底层,如果指向了一个重要的参数的空间,而你又不清楚直接就直接对其修改会造成程序或则是系统不可逆的错误。
2.野指针的产生
要避免野指针的产生最重要的是知道野指针是如何产生的。
野指针的产生最主要的三点
- 初始化指针没赋值
- 指针越界
- 指针指向的空间释放
指针没赋值在上面已经说过了,那剩下两条是什么呢
2.1 指针越界
在数组中最容易出现指针越界的情况的,看下面的代码
#include <stdio.h>
int main(){
int arr[10] = 0;
int *p = arr;
for(int i = 0; i <= 11; i++){
//当指针指向的范围超出数组arr的范围时,p就是野指针
*(p + i) = 1;
}
return 0;
}
已经超出了数组的范围,然后指向了数组后的空间,这个空间是未知的,使用就造成了野指针
2.2 空间释放
在使用指针指向一个函数中的一个变量,使用完函数,函数就被释放,函数中的变量的空间也会释放,并且地址也会重新分配,那这个时候指向函数中变量的指针也就变成了野指针。
3.避免野指针
这里给大家四条建议
- 指针初始化
- 小心指针越界
- 指针指向空间释放即用null占位
- 指针使用之前检查有效性
四、指针和数组
学数组的时候知道,数组名就是首元素的地址,在查找数组中的元素时用的是索引 []
位置,也可以用 +
的移动来找到元素。
很多人说数组就是指针,其实不对的,但你可以理解成指针,更多数组和指针的内容在后面。
五、指针的关系运算符
1.指针大小
每个类型都有每一个类型的大小,比如 char
是一个字节, int
为4个字节,
每个类型的指针也有大小的。
int* pa;//4个字节
float* pa;//4个字节
double* pa;//8个字节
char* pa;//1个字节
2.指针的移动
有了上面的知识我们可以对指针进行移动,移动的方法就是 +移动的长度
和-移动的长度
例如有一个 int
型的指针需要让它向前移动一位,就可以 +1
,如果要让它后退一位就 -1
。
而 int
型进一位是移动4个字节
char
型进一位是移动1个字节
总结
- 数据类型* 变量 = &变量
*变量
是指针中存放的具体的值,而变量
存放的是地址- 每个类型移动的字节是不一样的,要注意类型的长度
- 避免野指针的产生
C语言指针--一级指针的更多相关文章
- C语言用一级指针处理字符串的反思
1.一级指针处理字符串的常见方式 如果使用单个指针,不方便对字符串本身进行操作,只适合遍历. 使用两个指针, 两个指针和字符串大致有两个常见处理方式: (1)两个指针从字符串首部开始向后移动,同时处理 ...
- (C++)函数参数传递中的一级指针和二级指针
主要内容: 1.一级指针和二级指针 2.函数指针传递的例子 3.什么时候需要传递二级指针? 4.二级指针在链表中的使用 1.一级指针和二级指针 一级指针:即我们一般说的指针,就是内存地址: 二级指针: ...
- C语言复习:字符串和一级指针
字符串基本操作 字符数组初始化方法 int main() { //1 {}号法 初始化列表 //数组初始化有2种方法 默认元素个数.指定元素个数 char buf1[] = { ...
- C语言指针系列 - 一级指针.一维数组,二级指针,二维数组,指针数组,数组指针,函数指针,指针函数
1. 数组名 C语言中的数组名是一个特殊的存在, 从本质上来讲, 数组名是一个地址, 我们可以打印一个指针的值,和打印一个数组的值来观察出这个本质: int nArray[10] ={ 0 }; in ...
- C语言一级指针与二级指针
指针的概念 指针就是地址, 利用这个地址可以找到指定的数据 指针就是地址, 那么在使用的时候, 常常会简单的说 指针变量为指针 指针变量就是存储地址的变量 int *p1;// 申请了一个变量, 即在 ...
- 深入理解C语言中的指针与数组之指针篇
转载于http://blog.csdn.net/hinyunsin/article/details/6662851 前言 其实很早就想要写一篇关于指针和数组的文章,毕竟可以认为这是C语言的根本 ...
- 深入理解C语言中的指针与数组之指针篇(转载)
前言 其实很早就想要写一篇关于指针和数组的文章,毕竟可以认为这是C语言的根本所在.相信,任意一家公司如果想要考察一个人对C语言的理解,指针和数组绝对是必考的一部分. 但是之前一方面之前一直在忙各种事情 ...
- 由链表初始化看C语言的二级指针
先来看C语言创建链表.插入节点和遍历链表的一段代码: #include <stdio.h> #include <stdlib.h> typedef int ElemType; ...
- 论C语言中二级指针和二维数组之间的区别
刚开始学习C语言的时候,觉得一个数组可以定义一个一级指针去访问,想当然的就觉得可以定义一个二级指针去访问二维数组.很显然这是错误的. 我们来看看C语言的数组在内存中的存储方式. 实际上C语言中的数组, ...
- C语言二级指针(指向指针的指针)
转载:http://c.biancheng.net/cpp/html/85.html 指针可以指向一份普通类型的数据,例如 int.double.char 等,也可以指向一份指针类型的数据,例如 in ...
随机推荐
- 【总结】从++i思考计算机原子性和线程安全
在C++中,++i被认为是一种原子性操作,即不可分割的.不可中断的整体.它能够确保对变量的修改完整且正确,从而避免了数据竞争等问题,提高了程序的并发性和可靠性.然而,有些人可能会将原子性和线程安全混淆 ...
- 手记系列之四 ----- 关于使用MySql的经验
前言 本篇文章主要介绍的关于本人在使用MySql记录笔记的一些使用方法和经验,温馨提示,本文有点长,约1.5w字,几十张图片,建议收藏查看. 一.MySql安装 下载地址:https://dev.my ...
- Protobuf编码规则
支持类型 该表显示了在 .proto 文件中指定的类型,以及自动生成的类中的相应类型: .proto Type Notes C++ Type Java/Kotlin Type[1] Java/Kotl ...
- 工作中,Oracle常用函数
目录 1.序言 2.Oracle函数分类 3.数值型函数 3.1 求绝对值函数 3.2 求余函数 3.3 判断数值正负函数 3.4 三角函数 3.5 返回以指定数值为准整数的函数 3.6 指数.对数函 ...
- 【Azure 存储服务】使用 AppendBlobClient 对象实现对Blob进行追加内容操作
问题描述 在Azure Blob的官方示例中,都是对文件进行上传到Blob操作,没有实现对已创建的Blob进行追加的操作.如果想要实现对一个文件的多次追加操作,每一次写入的时候,只传入新的内容? 问题 ...
- Docker网络类型
Docker网络类型 目录 Docker网络类型 跟VMware对比 VMware Docker route命令 Docker的网络工作模式 Bridge模式 host模式 Container模式 n ...
- 2020-10-16:CAS知道么?底层实现? 会引发什么问题?如何解决ABA问题?
福哥答案2020-10-16:#福大大架构师每日一题# 简单回答:cmpxchg原子指令.aba,循环开销大,一个共享变量. [知乎](https://www.zhihu.com/question/4 ...
- 2022-04-27:Alice 有一个下标从 0 开始的数组 arr ,由 n 个正整数组成。她会选择一个任意的 正整数 k 并按下述方式创建两个下标从 0 开始的新整数数组 lower 和 hig
2022-04-27:Alice 有一个下标从 0 开始的数组 arr ,由 n 个正整数组成.她会选择一个任意的 正整数 k 并按下述方式创建两个下标从 0 开始的新整数数组 lower 和 hig ...
- save() prohibited to prevent data loss due to unsaved related object 'item_n
问题描述: save() prohibited to prevent data loss due to unsaved related object 'item_no 原因分析: 原来的目的是保存数据 ...
- 7-8 切分表达式——写个tokenizer吧 (20 分)
1.题目描述: [先说点出题背景] 这个题是为低年级同学.学C语言的同学准备的,因为,对这部分同学,这个题目编写起来略有一点复杂.如果是高年级.学过了正则表达式(Regular Expression) ...