再议C语言第二节(数组与指针)讲座整理

2024-05-25 15:18

本文主要是介绍再议C语言第二节(数组与指针)讲座整理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首先先区分一下两个容易混淆的定义:
数组指针是指向数组首元素的地址的指针,其本质为指针(这个指针存放的是数组首地址的地址,相当于2级指针,这个指针不可移动); 指针数组是数组元素为指针的数组,其本质为数组。例如:*p[2]是指针数组,实质是一个数组,里面的两个元素都是指针 []的优先级比*的优先级高,p先与[]结合,形成数组p[2],有两个元素的数组,再与*结合,表示此数组是指针类型的,每个数组元素相当于一个指针变量。
指针数组中的每一个元素均为指针,即有诸形如“*ptr_array[i]”的指针。指针数组中的元素亦可以表示为“*(*(ptr_array+i))”。又因为“()”的优先级较“*”高,且“*”是右结合的,因此可以写作**(ptr_array+i)。由于数组元素均为指针,因此ptr_array[i]是指第i+1个元素的指针。
                                              ————以上摘自百度百科
数组和指针的区别
首先对于编译器而言, 一个数组是一个地址,一个指针是一个地址的地址。 
数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。数组名对应着(而 不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。一般变量在内存单元中存放的是数据,指针变量在内存单元中存放的是地址。无论何种类型的指针都占4个字节的内存空间。 其中void和带有const的指针变量容易出错,void修饰指针代表的是一种不确定类型的指针,任何类型的指针都可以直接赋给它,无需类型转换,但是不能对void指针进行算术操作。当使用带有const的指针时其实有两种意思。一种指的是不能修改指针本身的内容,另一种指的是你不能修改指针指向的内容。先说指向const的指针,它的意思是指针指向的内容是不能被修改的。它有两种写法。
      const int* p; (推荐)
      int const* p;
      第一种可以理解为,p是一个指针,它指向的内容是const int 类型。p本身不用初始化它可以指向任何标示符,但它指向的内容是不能被改变的。
      第二种很容易被理解成是p是一个指向int的const指针(指针本身不能被修改),但这样理解是错误的,它也是表示的是指向const的指针(指针指向的内容是不能被修改的),它跟第一种表达的是一个意思。为了避免混淆推荐大家用第一种。
     再说const指针,它的意思是指针本身的值是不能被修改的。它只有一种写法
      int* const p=一个地址; (因为指针本身的值是不能被修改的所以它必须被初始化)
     这种形式可以被理解为,p是一个指针,这个指针是指向int 的const指针。它指向的值是可以被改变的如*p=3;
     还有一种情况是这个指针本身和它指向的内容都是不能被改变的,请往下看。
      const int* const p=一个地址;
      int const* const p=一个地址;
指向const的指针(指针指向的内容不能被修改)const关健字总是出现在*的左边而const指针(指针本身不能被修改)const关健字总是出现在*的右边,那不用说两个const中间加个*肯定是指针本身和它指向的内容都是不能被改变的。
  这次讲座欢神学长还讲了 左值与右值的概念:
在常见的C风格的语言中,有一些细微的地方是容易被忽视的,如表达式:a=b 这样的表达式在大多数编程语言中都是合法的,它是一个简单的赋值表达式,站在编译器的角度它又是怎么样对待与处理的呢?
      我们先温习一下,“地址”和“地址的内容”两个概念。在编译器看来,赋值运算符两边的a和b并不是两个地位平等的代号。这里的等号“=”并不代表a和b的地位平等,这里符号a的含义是a所代表的地址,习惯上我们称之为左值。而符号b的含义是b所代表的地址的内容,习惯上我们称之为右值,确切的说右值就是除了左值以外的值,他们可能是立即数和变量的某些组合。左值在编译时可知,表示存储结果的地方。通常只有允许修改的左值可以合法用作赋值运算符左边的操作数。所以尽管数组的名字表示“地址”,它是“左值”,但是它不是一个可以修改的左值,所以它也就不能用作赋值运算符的左操作数了,同理,用关键字const修饰的变量也是如此。编译器为每个变量分配一个地址(左值),虽然具体什么时候分配这个地址各个语言的编译器可能有所不同,但是变量在运行时会一直保存于这个地址。
      相对应的,存储于变量中的值(它的右值)只有在运行时才可知。如果需要用到变量中存储的值,编译器就发出指令从指定的地址读入变量值并将它存于寄存器中。也就是说,右值是运行时才会需要去用的实际值。于是"a=b;"的背后发生的事情大致就是,编译器会先检查操作数的合法性,如果操作数合法,就生成如下的指令:取b的右值(可能是一个立即数),将其保存至a的左值(一个地址)。在这里,a作为左值出现,但是实际其作用的是存储a的地址,这条语句的作用就是将这个地址存储的值赋值为b所代表的常量。b作为右值出现的时候就代表的是存储b的地址所存储的值,用语句表达就是*(&b)。先取到地址,再对该地址反引用取得这个地址存储的值。

这篇关于再议C语言第二节(数组与指针)讲座整理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1001870

相关文章

基于Python实现多语言朗读与单词选择测验

《基于Python实现多语言朗读与单词选择测验》在数字化教育日益普及的今天,开发一款能够支持多语言朗读和单词选择测验的程序,对于语言学习者来说无疑是一个巨大的福音,下面我们就来用Python实现一个这... 目录一、项目概述二、环境准备三、实现朗读功能四、实现单词选择测验五、创建图形用户界面六、运行程序七、

解决java.lang.NullPointerException问题(空指针异常)

《解决java.lang.NullPointerException问题(空指针异常)》本文详细介绍了Java中的NullPointerException异常及其常见原因,包括对象引用为null、数组元... 目录Java.lang.NullPointerException(空指针异常)NullPointer

使用Go语言开发一个命令行文件管理工具

《使用Go语言开发一个命令行文件管理工具》这篇文章主要为大家详细介绍了如何使用Go语言开发一款命令行文件管理工具,支持批量重命名,删除,创建,移动文件,需要的小伙伴可以了解下... 目录一、工具功能一览二、核心代码解析1. 主程序结构2. 批量重命名3. 批量删除4. 创建文件/目录5. 批量移动三、如何安

C++一个数组赋值给另一个数组方式

《C++一个数组赋值给另一个数组方式》文章介绍了三种在C++中将一个数组赋值给另一个数组的方法:使用循环逐个元素赋值、使用标准库函数std::copy或std::memcpy以及使用标准库容器,每种方... 目录C++一个数组赋值给另一个数组循环遍历赋值使用标准库中的函数 std::copy 或 std::

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要

C语言中自动与强制转换全解析

《C语言中自动与强制转换全解析》在编写C程序时,类型转换是确保数据正确性和一致性的关键环节,无论是隐式转换还是显式转换,都各有特点和应用场景,本文将详细探讨C语言中的类型转换机制,帮助您更好地理解并在... 目录类型转换的重要性自动类型转换(隐式转换)强制类型转换(显式转换)常见错误与注意事项总结与建议类型

Go语言利用泛型封装常见的Map操作

《Go语言利用泛型封装常见的Map操作》Go语言在1.18版本中引入了泛型,这是Go语言发展的一个重要里程碑,它极大地增强了语言的表达能力和灵活性,本文将通过泛型实现封装常见的Map操作,感... 目录什么是泛型泛型解决了什么问题Go泛型基于泛型的常见Map操作代码合集总结什么是泛型泛型是一种编程范式,允