IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> c语言数组和指针基础 -> 正文阅读

[C++知识库]c语言数组和指针基础

本博客大量参考 《c primer plus》 ,希望以后复习舒服些

前言

在c/c++语言中,我们都是用过数组和指针,但一开始的时候肯定是不怎么顺手的,会犯很多错误,最难使用的还是c语言的内置类型数组和内置类型指针,由于c++出现的较晚,吸收了c语言的精华,又有自己的新家伙,比如动态数组vector,智能指针等。但是我们同样需要了解最基本的,才会尽最大可能使用c++的工具时不会出现太大错误。
本篇博客依据c语言的内置类型数组和内置类型指针来叙述。

数组(数组的下标从零开始

数组 : 由数据类型相同的一系列元素组成。在使用数组时,要通过声明告诉编译器数组中有多少个元素元素的类型是什么。

我们通过代码看看数组的声明和初始化:

#include<stdio.h>
int main(){
     //声明但不初始化数组,数组里面的存储元素均为垃圾值
	 int array[5];//array 里面有5 个 int 类型的元素 
	 float array_1[2];//  array_1 里面有 2 个float 类型的元素 
	 
	 //数组的初始化
	int apple[6]={1,2,3,4,5,6};//从 ANSI C 开始支持这种初始化
	int arr[5]={1,2,3}; //编译器会把后面的两个int 类型的元素置为0  // 即元素 为  1,2,3,0,0
			
			
			
	//int ar[6]={0,0,0,0,0,1}; //传统的语法
	// c99 可以指定初始化器 
	int ar[6]={[5]=1};// 把 ar[5]初始化为 1,数组内部其他int 类型置为0,//即元素为 0,0,0,0,0,1 
			 
	return 0;
} 

c语言的数组要求严格,不允许数组间的赋值,但是c编译器不会检查数组数组越界情况和数组索引的正确性

int arr[3];
int app[4];
app=arr;// [Error] assignment to expression with array type

数组下标越界可能会导致程序崩溃,使用数组不越界是程序员的责任

数组的[ ] 的值要求是整形常量表达式
类型与 1 这个就是 整形常量,sizeof表达式被视为整形常量
并且在 [ ]内部的值必须要大于0

int array[sizeof(int)] //ok  整形常量表达式
int arr[-1] //error  数组大小必须大于0
int arr[0] // error 数组大小必须大于0
int arr[1.2] //error  数组大小必须是整形
int arr[(int)1.2] // ok  已经强转成整形

c 99 允许了一种数组的声明,叫 变长数组(VLA)

int a=3;
int arr[a] //ok

这种数组,先不介绍了。


当我们不想改变数组里的元素时,我们可以使用const限定符,来表示该数组只读,不准修改里面的变量。

#include <stdio.h>
int main()
{          /*letting the compiler count elements */
    const int days[] = {31,28,31,30,31,30,31,31,30,31};//表示一年的月份的天数,闰年除外 
    int index;
    for (index = 0; index < sizeof days / sizeof days[0]; index++)
     printf("Month %2d has %d days.\n", index +1,
               days[index]);
     days[1]=29; //	[Error] assignment of read-only location 'days[1]'
    return 0;
}

现在我们要重复刚才的几句重要的话,相当重要的话:
1,数组具有容器的特性 ,数组存放相同的数据类型
2,数组的大小必须在编译时给出来
3,数组中的元素在内存中是连续排列的,因此支持随机访问
4,用数组时放在[]中的数字叫做下标,数组的下标从零开始,下标必须大于0
5,数组下标越界可能会导致程序崩溃,使用数组不越界是程序员的责任
6,大多数的时候数组名代表数组开始的地址(有两个特例)(马上讲指针的时候要讲到

指针(内置类型)

指针是一个值为内存地址的变量
那指针既然是变量,变量肯定是可以被赋予值的,是的,可以,赋予指针的值就是其他变量的物理地址,我们通过使用 &运算符 得到一个变量的物理地址


int* ptr=NULL; //ptr是一个指针变量,类型为 int* .
int a=3; //a 是一个int 变量,在内存有物理地址 ,&3
ptr=3;// c 语言 GCC 编译器会 给出 warning ,说明 c 语言的类型检查不严格,c++ 会给出 error  不要忽视warning
ptr=&3; //指针已经获得了变量a 的地址
int b=*ptr; //使用解引用运算符,得到指针所指向的地址的值

好了,我们现在已经会了指针的基本用法了,指针代表操控数据的地址就等于操纵数据,大家多多练习。
我们将通过指针和数组来继续探讨它们更高级的用法。
下面我们来看看指针和数组

指针和数组

这里大家要记住一句话,数组的名字代表地址,它代表数组开始的地址,
来看图片:
在这里插入图片描述
所以,我们可以使用指针来操作数组!

 float array[5]={1,2,3,4,5} //这是一个float 类型的数组,内含5个数据元素
 float* ptr=array; //将数组的首地址赋给ptr,由于数组名就是地址,所以我们不能使用& ,加上它就会变成另外的意思了!
 for(size_t i=0;i<5;i++){
   printf("%p",*(array+i)); // 使用指针遍历数组
}

我们现在给出书中的一个代码,更为详细:
代码来源(c primer plus)

// pnt_add.c -- pointer addition
#include <stdio.h>
#define SIZE 4
int main(void)
{
    short dates [SIZE];//这是一个short类型的数组,内含4个元素  
    short * pti;  //这是指向short类型的指针 
    short index;  //这是声明一个变量 
    double bills[SIZE]; //这是一个double类型的数组,内含4个元素 
    double * ptf; //这是指向double 类型的指针 
    
    pti = dates;    // assign address of array to pointer
    ptf = bills;
    
    printf("%23s %15s\n", "short", "double");
    for (index = 0; index < SIZE; index ++)
        printf("pointers + %d: %10p %10p\n",
          index, pti + index, ptf + index);
    
    return 0;
}

在我的系统电脑里,short占用2个字节,double占用8个字节,以下为gcc 编译器执行后的exe,
在这里插入图片描述
我们需要记住一句话:指针加1,递增的是它所指向类型的大小
接下来博主就直接写出指针的用法总结了(内置类型的指针都包含的特点,而c++ 将迭代器(广义指针)设置了不同的等级,具体的了解可以去百度)
1,赋值:指针之间可以直接赋值,但要注意等号两边类型的兼容性,(c 语言的类型检查没有c++严格,c语言可以将数字赋予指针,但c++不行)

int* ptr1=& 1;//ptr1 是一个int* 类型的指针变量,里面存的是1的地址
int* ptr2; //ptr2 是一个int* 类型的指针变量
ptr2=ptr1;//指针间的赋值,将ptr1变量里的内容(地址)赋给ptr2
来看张图片
在这里插入图片描述
(这个博主也不咋明白的)
这种内置类型的指针指向栈区和静态存储区,赋值还是不容易出错的,但当内置类型的指针指向堆区存储时,就会出现很多问题,比如:
如图中我们所看到的,两个指针指向同一个内容,若释放内存时,极易发生操作失误,这就是深拷贝和浅拷贝的问题,大家可以自行去百度。)

2,解引用操作:我们可以使用 * 这个运算符来获得指针变量存储的内容
3,取地址:由于指针也是变量,那变量肯定会在内存有地址的,我们可以对指针是用 & ,来获得指针的地址。
4,指针和整数进行相加:这样获得的也是指针,只不过是修改了指针的步长,使用指针处理数组时经常使用
5,递增指针:当指针指向数组时,递增指针,如前面说的: 指针递增,递增的是它所指向类型的大小
6,指针减去一个数
7,递减指针
8,指针求差:两个指针可以相减的前提是:这两个指针指向同类型数组,我们得到的是距离
9,进行比较:两个指针可以比较的前提是:这两个指针指向同类型数组
10,用作循环的判断条件:我们可以在一些循环表达式中使用,进而判断
以上,大家无需用口记忆,多多练习即可

接下来我们将几个重要的公式:

int array[5]={1,2,3,4,5};
int* ptr=arrar;
/*下面的两个等式是相同的*/
*(array+2)=array[2]; //均是取数组的元素

/*下面的两个等式是相同的*/
array+2=&array[2]//均是取数组元素的地址

多多练习,自然就记住了。

指针和递增运算符和解引用运算符联合使用
有时候,我们在看一些高手写的代码时,他们经常会把几步骤的代码写成一行,比如:

*p++
*++p
(*p)++
这该如何理解你?

我们先看书中的代码把:

#include <stdio.h>
int data[2] = {100, 200};
int moredata[2] = {300, 400};
int main(void)
{
    int * p1, * p2, * p3; //定义指针 
    
    p1 = p2 = data;
    p3 = moredata;
    printf("  *p1 = %d,   *p2 = %d,     *p3 = %d\n",
           *p1     ,   *p2     ,     *p3);
    printf("*p1++ = %d, *++p2 = %d, (*p3)++ = %d\n",
           *p1++     , *++p2     , (*p3)++);
    printf("  *p1 = %d,   *p2 = %d,     *p3 = %d\n",
           *p1     ,   *p2     ,     *p3);
    
    return 0;
}

来看运行结果;
在这里插入图片描述
分析:
一元运算符 * 和 ++ 的优先级相同,但结合律从左到右,
*p1++:
p1++ : 它先进性表达式运算,返回的指针是计算之前的指针:

i++ 的类似实现是 :
int temp ;
temp=i;
i=i+1; //进行表达运算
return temp; // temp记录的是之前 i的值,返回之前的值

在开始进行*p1;所以得到的是序列的第一个值,100

*++p2: 先递增指针,

++ i的类似实现
i=i+1;
return i // i的值已经得到递增了

再 进行 *p2// 这时指针已经指向下一个元素了
所以得到的是序列的第二个元素! 200

不过要说明的是:
++i 和 i++ 都可以使 i 进行递增,不过要在 赋值方面注意两者的区别即可

(*p3)++: 这个应该比较好分析, 指针解引用后值进行了 +1 , 得到 301

说明: ++ p1 和p2++ 都没有改变数组的值,而 (*p3)++确改变了数组中的值。

好了,这次的博客就到这里了。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-13 09:05:31  更:2021-09-13 09:07:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 23:27:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码