十一、指针运算与一维数组

  多数变量都能进行算数运算,但并非全部变量均可以。幸运的是,指针变量能做算术运算操做。除了引用和解引用内存地址外这也是指针的最重要的用途之一。数组

  内存是连续块排列,这天然让咱们想到了数组数据类型,由于数组索引也是连续排列。数据结构

一、数组内存排列

  数组是最基本的数据结构之一。更具定义数组是相同数据类型的集合,内存排列里占用连续内存单元并可经过索引进行访问。spa

下面代码演示的内存转储。3d

#include <stdio.h> #include <stdlib.h> #include <string.h>

void main() { int iArray[32]; int i; for (i = 0; i < 32; i++) { iArray[i] = i; } for (i = 0; i < 32; i++) { printf("a[%d] %u %d", i, &iArray[i], iArray[i]); if ((i % 4 == 0)&&(i!=0)) printf("\n"); } }

运行结果:指针

  仔细分析上面的内存转储,会发现每一个连续的数组索引器内存地址也是连续的。例如:第0个数组索引a[0]的地址为7338376,第一个数组索引地址为7338380,后一个内存地址减去前一个连续的地址(&a[1]-&a[0]=4).结果为4.由于一个整型变量内存中占用一个字长(32位/4字节)。因此变量a[0]内存地址为7338376~7338380。code

 字节序

  字节序描述数据将存储在内存时的格式/排列。加载/存储指令从内存读取数据,在运行完数据处理指令后从寄存器将数据写会内存。blog

  在存储和加载时,CPU必须采用硬件支持的字节序格式。其可分为大端和小端。一个字长为4字节/32位。咱们假设将0x1234存储到变量中。索引

  (1)大端时,高字节存储在第一个位置,次高字节存储在存储次邻位置,并以此类推。ip

  (2)小端是,低字节存储在第一个位置,次高字节存储在存储次邻位置并以此类推。内存

下面经过一个示例检测咱们的系统是打断仍是小端:

#include <stdio.h>

#define BIG_ENDIAN 0
#define LITTLE_ENDIAN 1

int endian() { short int word = 0x0001; char *byte = (char*)&word; return(byte[0] ? LITTLE_ENDIAN : BIG_ENDIAN); } void main() { int value; value = endian(); if (value == 1) { printf("大端\n"); } else printf("小端\n"); }

运行结果以下:

二、指针运算

  指针运算能进行使用以下操做符:

++
--
+
-

值得注意的是:不容许使用除法(/)和乘法(*)操做符。

  在以前的字节序中讲过了,内存中数据是连续排列的。能利用数组索引访问内存块中相邻的每一个数组元素,这也是指针的一种常见操做。

例如:int arry[10]//包含10个整数的整型数组。

int* ptr; ptr=arr;//数组第一个索引的指针

一、指针加法

  +操做用于加法处理,指针指向某个数据类型时,它始终指向数据类型在内存单元中的首字节。在指针运算中,作加法运算后指针变量指向的地址取决于有数值与数据类型相乘表达式的值。下面给出一个示例:

#include <stdio.h>

int main() { int i = 0; int data = 9; int *iptr; char *cptr; iptr = &data; cptr = (char*)&data; printf("value of data=%d,hex value =%x\n", data, data); printf("Address of data=%p\n", &data); printf("整型指针指向:%p\n", iptr); printf("char型指针指向:%p\n", cptr); for (i = 0; i < 4; i++) { printf("address =%p value=%x\n", cptr, *cptr); cptr++; } return 0; }

程序运行结果以下;

  不难看出值为9的int变量占用了四个字节,从00B3FC78~00BCFC7B.这里调用char指针来讲明这个事实。

  其实咱们若是查看汇编输出咱们会发现,指针运算中编译器会作如下转换:

<指针变量>=<指针变量>+<增长值>

<指针变量>=<指针变量>+<指针变量数据类型大小>*<增长值>

 值得注意的是,指针变量+指针变量是合法的,可是不容许将指针变量加入到另一个指针变量中。

二、指针减法

   同理的,指针运算中对于指针减法会作如下转换:

<指针变量>=<指针变量>-<增长值>

<指针变量>=<指针变量>-<指针变量数据类型大小>*<增长值>

可是与指针加法不一样,两个指针变量能够作减法,下面给出一个代码示例:

#include <stdio.h>

int main() { int data[4] = { 1,2,3,4 }; int *iptr1; int *iptr2; int val; iptr1 = &data[1]; iptr2 = &data[2]; val = iptr2 - iptr1; printf("两个指针地址之间的距离为:%d\n", val); return 0; }

运行结果以下:

结果为1是由于这两个连续位置之间只存在一个元素。当两个指针变量分别指向数组连续内存地址的不一样位置,让它们彼此相减获得的结果差表示两个指针变量间存在的元素数目。

 

三、一维数组

  想要了解指针和数组之间的使用与相关性,必须探究有关数组变量经常使用语法的意义。这里顺便重提一下数组的定义:存储在连续内存单元内的一系列的数据类型值。

  前面提到的数组索引咱们知道

数字名=&数组[0]

  若是咱们增长它的偏移量技能便利数组数据元素的连续地址。

咱们能够认为

arr_var+offset=&arr_var[offset] 和 (arr_var+offset)=arr_var[offset]

下面进行给出一个相关示例:

#include <stdio.h>

int main() { int arr[4] = { 1,2,3,4 }; printf("地址为%p\n", arr); printf("地址为%p\n", &arr[0]); return 0; }

运行结果以下:

值得注意的是:虽然数组变量名表明数组的第0个索引地址,但禁止修改它的值,即不能让它指向其余位置。以下:

int arr_var[5]; arr_var=arr_var+1;//这样作是不容许的,由于表达式试图将数组名指向下一个整数变量的地址。
arr_var++;//非法语句,试图修改数组变量的起始地址

一、动态数组

   有时在数组定义时不知道要存储的数组元素数目。程序运行时,数组元素数目可能增长也可能减小。全部咱们在数组中存储这类元素时,数组必须是动态的,由于数组大小在运行时能改变。诸如咱们以前的定义

int arr_stat[10];

  该声明确保编译时已知数组大小,称为静态数组。

  指针可以帮助咱们操做内存区域实现根据需求增长或下降内存的预期行为。利用指针和堆实现该目标。调用malloc()在堆中分配内存。下main咱们用一个示例进行演示。

示例:需求:用户插入数据时,适当调整内存大小以存储数据元素。用户删除数据时,释放内存。

 

#include <stdio.h> #include <malloc.h>
int *ptr = NULL; static int count = 0; void insert(int data) { if (ptr == NULL) { ptr = (int*)malloc(sizeof(int));//从对分配空间给第一个data单元
        ptr[0] = data;//利用数组符号访问内存地址来存储数据。
 } else { ptr = (int*)realloc(ptr, sizeof(int)*(count + 1)); ptr[count] = data;//利用数组符号访问内存地址来存储数据。
 } count++; } void show() { int i = 0; for (i = 0; i < count; i++) { printf("%d\n", ptr[i]); } } int main() { int c = 0; int data; while(c!=3) { printf("输入选择\n"); printf("输入1插入数据\n"); printf("输入2显示数据\n"); printf("输入3退出数据\n"); scanf("%d", &c); if (c == 3) break; switch (c) { case 1: printf("数据=\n"); scanf("%d", &data); insert(data); break; case 2: printf("数组中的数据\n"); show(); break; } } return 0; }

 运行结果:

二、指针数组

   按照定义指针数组是指在连续单元内存中在储指针变量。该数组中每一个位置包括内存中某个数据的内存地址。

指针数组声明:<数据类型*><变量名>[数组元素数目]

int * arr_ptr[10]//指向10个整型变量

 示例:

#include <stdio.h>
int main() { int arr[4] = { 1,2,3,4 }; int* arr_ptr[4]; int i; for (i = 0; i < 4; i++) { arr_ptr[i] = arr + i; } printf("数组元素地址为\n"); for (i = 0; i < 4; i++) { printf("元素%d的地址为%p\n", i, arr + i); } printf("数组元素的值为\n"); for (i = 0; i < 4; i++) { printf("元素%d的值为%p\n", i, arr_ptr[i]); } return 0; }

运行结果为:

分析上述输出,指针数组arr_ptr包含数组arr中每一个元素的地址。

二、数组指针

  依据定义数组指针为指向数组的指针变量。

声明:<数据类型>(*<变量名>)[数组元素数目]

例如:

int (* ptr2arr)[4];//指向包含长度为4数组的指针

  与其余指针变量同样,数组指针每次仅能指向一个位置。

示例:

 

#include <stdio.h>
int main() { int arr[4] = { 1,2,3,4 }; int(*ptr2arr) [4]; int i; int *ptr = arr; ptr2arr = &arr; for (i = 0; i < 4; i++) { printf("元素的地址为%p\n", arr + i); } printf("值在%d\n", *(ptr2arr[0] + 1)); for (i = 0; i < 4; i++) { printf("地址%p的值为%d\n", (ptr2arr[0] + i), *(ptr2arr[0] + i)); } return 0; }

运行结果以下;

ptr2为数组指针,指向存储四个整型类型的数据元素的数组。

相关文章
相关标签/搜索