你必须知道的指针基础-2.指针的声明和使用及数组和指针的关系

一、计算机知道数据类型吗?

1.1 神奇的数据类型

  At first,计算机中绝大部分数据都放到内存中的,不同的数据放到不同的内存区域中。But,内存角度没有数据类型,只有二进制;数据以字节(8位二进制)为单位存取。不同数据类型占据不同的字节,例如在32位系统中:int 为4个字节,short为2个字节(下面如未特殊声明,均为32为系统环境下的说明)。下面我们看看int类型、short类型和double类型的数字分别在内存中如何存储:

  ①int类型:99999

  由于int类型占4个字节,每个字节8位,所以在内存中会有如上图所示的四个字节来存储99999的二进制。其中,0001~0004是内存中的编号。为了验证,我们可以通过科学计算器来将99999转换为二进制看看:

  由于int类型在内存占四个字节,每个字节8位,那么一共应该有32位。所以,可以看到内存编号0001中是自动补充的0,而0002中则补充了7个0。后面0003和0004则是转换后的二进制数。验证结束,发现跟上图所示的一模一样。

  ②short类型:8888

  由于short类型只占2个字节,所以在内存中会有如上图所示的两个字节来存储8888的二进制。

  ③long类型:9999

  由于long类型占8个字节,所以内存中会出现8个字节来存储9999的二进制。

PS:由于内存只管存储,不知道数据类型,所以我们可以知道,所谓的数据类型都是程序语言编译器在识别和标注。也就是我们所说的,要取几个字节,从哪里开始到哪里结束,都是编译器在帮我们做,内存是不管的。

1.2 C程序中神奇的&

  假如有下面一段代码,声明了两个int类型的整数,其中&i表示:获得变量i所指向内存的地址,地址也是数字。

int i = 5;
printf("%d\n",&i);

int j = 5;
printf("%d\n",&j);

  那么,我们可以通过程序输出的结果来验证在内存中的地址是否是一个数字,以及是否满足上面所说的字节长度:

  可以看出,两个int类型的变量的内存地址的确是数字,并且相差4个字节。(这里要说明的是在堆栈中,内存地址的分配是从高位到低位,所以这里第一个变量的内存地址比第二个变量的内存地址的数字要高)

PS:在.NET中,数据类型分为值类型和引用类型。其中,值类型被分配在栈上,引用类型被分配在堆(托管堆)上。

(1)栈高效而灵活,并且可以自动销毁变量,回收空间,但对于处理大容量的数据还是不够;

(2)堆可以存储大容量的数据,但是无法自动回收内存,需要借助于GC(垃圾回收机制)来实现,于是也就有了.NET中的托管堆。

  既然&是取地址,那么就可以用int类型存储指针地址:

int j=5;
printf("%d\n",&j);

int iAddr = &j;
printf("%d\n",iAddr);

  查看结果后会发现,iAddr也会显示地址。其实,short、long、char等的地址都可以用int表示。But,如果用int表示各种指针,那么就不知道内存中到底放的是什么类型(其实内存中也不知道是什么类型,都是一堆字节数据而已)。所以,也就有了指针,在实际中一般用“类型指针”来表示,其结果是一样的。

int *iPtr = &i;
printf("%d\n",iPtr);

二、指针的声明与使用

2.1 神奇的*号

  (1)声明

  在C中,可以用*号来声明一个指针,通常都是用具体要指向的类型的指针来指向目的变量。这样的指针就叫做“类型指针”,也就使程序语言知道要从内存中取几个字节了。

int i = 5;
int* iPtr = &i; // 类型化的指针,知道是从内存中取几个字节
printf("%d\n",iPtr);
int i1 = *iPtr;
printf("i1=%d\n",i1); // 取iPtr指针指向的内存中的数据

  (2)使用

  可以使用*取指针指向的内存数据,如上面代码中的 i1 = *iPtr。下面来看看代码的运行结果:

  还可以通过指针修改变量的值,例如我们可以写以下代码操作iPtr指针来修改i的值:

*iPtr = 100;
printf("i=%d\n",i);

  这下i的值也变成了100。(可以理解为把100存入到iPtr所指向的内存中)

2.2 小结

*的两个用途:

(1)声明的时候用来声明指针变量: int *iPtr;

(2)除了声明变量的时候,其他时候*用来表示获取指针指向的数据。

&用来获取变量的地址。

三、数组和指针

3.1 一块连续的内存区域

  我们经常听说:数组在内存中是一块连续的内存区域,那么来验证一下,声明一个数组,并依此输出其内存地址:

int nums[] = {33,55,66,77,88};
for(int i=0;i<5;i++)
{
    printf("%d\n",&(nums[i]));
}

  输出结果如下图所示:可以看出,各个内存地址数字均只差4个字节,是连续的。

3.2 指针如何指向数组

  在开发中一般使用第二种方式,即数组元素的名字即是数组第0个元素的内存地址。

int* iptr1 = &(nums[0]); //获取第0个元素的内存地址
int* iptr2 = nums; //一般这样用,数组元素的名字就是“第0个元素的内存地址”

3.3 字符串即字符数组

  在计算机中没有字符串的概念,都是用字符数组在表示字符串。因此,字符串也就是“以\0结尾的一段连续的char内存区域”。

    char  str1[] = "helloedison";
    char* str2 = str1;
    printf("str1=%c\n",str1[0]);
    printf("str2=%c\n",*str2);

  可以看到,使用指针str2指向了str1的第0个元素的地址,输出结果验证了一致性:

参考资料

  如鹏网,《C语言也能干大事(第三版)》

作者:周旭龙

出处:http://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

时间: 2024-10-01 04:14:17

你必须知道的指针基础-2.指针的声明和使用及数组和指针的关系的相关文章

关于数组以为指针二维指针的应用举例

事实上,计算机系统的多维数组其实最终还是以一维数组的形式实现的.就N x M的二维数组来讲,设其数组名为array.指针array指向一个数组,该数组存放的是一系列指针,这些指针分别指向相应的一维数组,而这些数组中存放的才是我们的数据. 由此array 是第i个指针变量地址,array[j]则表示相对于第i个指针变量偏移j*sizeof(数组类型).系统通过这种机制访问了该二维数组的第i行,第j列的内容.有上述可知,指向二维数组的指针其实是指向“指针变量地址”的指针变量.所以在声明指向二维数组的

程序设计基石与实践系列之类型提升、内存分配,数组转指针、打桩和矢量变换

英文出处:Peter Fa?ka: Guide to Advanced Programming in C C语言可用于系统编程.嵌入式系统中,同时也是其他应用程序可能的实现工具之一. 当你对计算机编程怀有强烈兴趣的时候,却对C语言不感冒,这种可能性不大.想全方位地理解C语言是一件极具挑战性的事. Peter Fa?ka 在2014年1月份写下了这篇长文,内容包括:类型提升.内存分配,数组转指针.显式内联.打桩(interpositioning)和矢量变换. 整型溢出和类型提升 多数C程序员以为,

直观理解C语言中指向一位数组与二维数组的指针

一维数组和指针: 对于一位数组和指针是很好理解的: 一维数组名: 对于这样的一维数组:int a[5];  a作为数组名就是我们数组的首地址, a是一个地址常量 . 首先说说常量和变量的关系, 对于变量来说, 用箱子去比喻再好不过了, 声明一个变量就声明一个箱子,比如我们开辟出一个苹果类型的箱子, 给这个变量赋值就是把盛放苹果的箱子中放入一个实实在在的苹果, 这就是变量的赋值.  而对于数组来说, 就是一组类型相同的箱子中,一组苹果箱子, 可以放入不同的苹果. 一维数组空间: 变量被声明后, 我

《你必须知道的495个C语言问题》笔记--数组和指针

一.如何动态分配多维数组? 1.分配一个指针数组,然后把每个指针初始化为动态分配的行 代码如下: int **array = (int **)malloc(ROW * sizeof(int*)); int i = 0; for(i=0; i<ROW; i++){ array[i] = (int *)malloc(COL * sizeof(int)); } 2.让数组的内容连续,但在后来重新分配行. 代码如下: int **array = (int**)malloc(ROW * sizeof(in

《征服 C 指针》摘录3:数组 与 指针

一.数组 和 指针 的微妙关系 数组 是指将固定个数.相同类型的变量排列起来的对象. 正如之前说明的那样,给指针加 N,指针前进“当前指针指向的变量类型的长度 X N”. 因此,给指向数组的某个元素的指针加 N 后,指针会指向 N 个之后的元素. #include <stdio.h> int main(void) { int array[5]; int *p; int i; /* 给数组 array 的各元素设定值 */ for (i = 0; i < 5; i++) { array[i

C语言学习004:数组与指针

在C语言中,字符串实际上就是字符数组,在内存中字符串"Shatner"存储的形式是这样的 由于C语言并不知道数组有多长,所以用"\0"表示字符串的结束位置,通过sizeof运算符可以取到字符串在内存中占用多少个字节 同样的字符串在下面的代码中获取的长度却不一样,你知道是什么原因么? #include <stdio.h> void SayHello(char msg[]){ printf("msg occupies: %i\n",siz

C++数组,指针,引用以及三者的复合类型

C++数组,指针,引用以及三者的复合类型 这里省去了对这三者的单独介绍,仅仅介绍使用这三者组成的组合类型. 一.两两组合 这三者的两两组合有9种: 数组 指针 引用 数组 数组的数组 数组的指针 数组的引用 指针 指针的数组 指针的指针 指针的引用 引用 引用的数组 引用的指针 引用的引用 1.指针的指针.数组的数组.数组的指针.指针的数组 指针的指针(二维指针),数组的数组(二维数组),数组的指针和指针的数组这里就不介绍了,很多博客文章书籍都有详细的介绍.它们的形式是: 指针的指针: int*

C的日记-数组和指针

[数组] C语言中数组名表示该数组的起始地址,即给数组本身对应的值就是一个地址,而数组中的值就是从起始地址开始的不同的地址内的值. 如:char c[9];        //定义时的数组char c[5]中的c和运算时的c是一个含义,都是数组首地址     scanf("%s",c);     printf("%d",c); // printf(%s,c) 输入:china 输出:2686675.输出的是字符数组首地址. 若换为后面一个,输出china,输出chi

二维数组及指针

首先,看一维数组. []符号是下标运算符,a[i]就是*(a+i) 那么a[i][j] 就是*(a[i]+j)=*(*(a+i)+j) 本人对二级和多级指针的理解:1.抽象上说二级指针的内容是地址的地址.变量A好像跟你捉迷藏似的,你要想找到A,你先得去一个地方把A的地址给找出来,然后再根据这个地址找到A.就类似武侠电影里的宝藏,你要先去一个人的背上发现藏宝图,然后再根据藏宝图里画的地址找到宝藏,在这里,这个人的背就是一个最外层的地址,藏宝图就是内层的地址.2.对于二级指针和多级指针,定义时,我们