c语言-指针数组

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013862108/article/details/83933394

指针

内存和地址怎么理解呢?

机器中有一些位置,每一个位置被称为【字节】/byte,许多现代机器上,每个字节包含8个位。更大内存单位【字】,通常包含2个或4个字节组成。

一个字包含4个字节,它的地址是什么?

他仍然只有一个地址,是最左边还是最右边的那个字节的位置,取决于机器。

机器事实-关于整型的起始位置:

在要求边界对齐(boundary alignment)的机器上,整型存储的起始位置只能是某些特定的字节,通常是2或4的倍数。

变量名和地址关系?

所有高级语言的特性之一,就是通过名字而不是地址来访问内存的位置。那么名字和地址是怎么关联的呢?关联关系不是硬件所提供的,它是由编译器实现的,硬件仍然通过地址访问内存位置。

存储在内存的一个32位值,到底是整型还是浮点呢?

什么类型取决于使用方式,如果使用整型算术指令,这个值就被解释为整数,如果使用浮点型指令,他就是个浮点数。

指针变量他的地址对应的内存中存的是什么内容?

存储是一个值,这个值,通常被当做地址来使用。

对于int a=112; int *d = &a;  为什么编译器最终将a的地址写入d对应的内存空间,而不是把112写入d的内存空间呢?

原因应该是这样设计灵活,且效率高,更重要的是硬件的设计如:RAM 有地址这个概念

符号* 什么含义?

用来执行间接访问操作。对一个变量间接访问,声明含义?就是不把这块内存值直接使用,而是把它用作地址,把这个地址对应的内容取出。

指针未初始化是什么含义,有什么风险?对未初始化的指针访问会发生什么?如int *a  ;  *a=12;

这个操作可能会有下面情景发生

     1.  运气好a 的初始值是非法地址,出错,终止程序,在unix系统上这个错误memory fault  ,在windows出现一般保护性异常(general  protection exception)

     2.更严重的情况,这个指针偶尔可能包含一个合法地址,即是这样的情况:引发错误的代码,与原先用于操作那个值得代码完全不相干。

编译器能检测出来初始化的指针p,   *p = 12,这样,并给出警告吗?

标准定义的NULL指针什么含义?我怎么定义一个NULL指针变量?怎么判断一个指针是不是NULL指针。

表示不指向任何东西。定义一个变量赋值为零。与零值比较来判断指针是不是NULL指针。

在机器层面NULL指针内容到底是什么呢?

NULL 指针可能不是0,在此情况,编译器将负责零值和内部值之间的翻译和转换。

对一个NULL指针间接访问会出现什么情况?

因编译器而异,有的不报错。有的发生错误,并终止程序。

怎么定义一个指针变量才是好习惯?

如果你已经知道指针将被初始化为什么地址,就把它初始化为该地址,否则把它初始化为NULL。

在对一个变量赋值时,编译器会校验,检查什么?

         校验,使用变量类型和应该使用的变量的类型不一致时,编译器会报错。

         分析下*&a = 25;  非重点

指针常量是什么能不能访问操作并赋值?

*100 = 25;  *100 就是指针常量。这条语句是非法的,需要强制类型转换如:

 *(int *) 100 = 25;

指针常量什么样情况才能用到?

        如:与输入输出设备控制器通信。

指针的指针怎么用示意图画明白?

指针定义和使用的分析:

定义(包括声明和初始化)

    声明的分析:有就是指针;初始化,左值使用,*【变量】代表是将右边的值写入指针变量内存中(【变量】);

    **【变量】左值使用,赋值,*【变量】表示地址内存打开,打开结果还是地址,**【变量】表示多次打开,还是代表打开地址,注意编译器能知道这种变化,**两次就是二级指针

    使用:*【变量】是右值表达式*代表间接访问,把【】中当做地址使用,找到这个地址对应的内存单元,把值拿出来,就是*【】表达式的值了

 

注意* 是右结合性

Int a =12;

Int *b = &a;

Int **c = &b;

画图要点:

    1.箭头===》是地址

    2. 虚线。表示关系

    3. 实线。表示*访问

粗椭圆  当做右值使用,使用表达式的值。

粗方框  当做左值使用,指地址。

#include <stdlib.h>
#include <stdio.h>
int
main(){
        int a=12;
        int *b=&a;
        int **c= &b;

        printf("%p %p %p \n",a,b,c);
        printf("%d %d %d \n",sizeof(a),sizeof(b),sizeof(c));
//      printf("%s %s %s \n",a,*b,*c);
        printf("%d %d %d \n",a,*b,**c);
}

结果:

分析结果:  指针占用八个字节,地址占用八个字节,实际上用6个字节表示地址(0x开头)

例子 :指针要用对等的地址

#include <stdlib.h>
#include <stdio.h>
int
main(){
	int a=12;
	int *b= &a;
	int **c= &a;
	
	printf("%p %p \n",a,c);
	printf("%d %g \n",a,*c);
	printf("%d %d \n",sizeof(a),sizeof(c));
}

结果:编译器报错!

结果分析:指针要用对等的地址(或低一级指针赋值如&b, 或者同级别指针&d)来赋值,编译器会检验出不符合的情况

为什么&ch 不能用作左值?

&ch结果会存储在某个地方/某个内存,但是我无法知道他位于何处,这个表达式,看不出他在机器中那个特定位置,所以它不是一个合法的左值。

什么是左值,右值?

 左值可以再“=”号左侧,也可以在等号右侧,而右值只能出现在等号右侧。

分析清楚一个指针表达式是左值还是右值有什么好处?

分析表达式?

Char  ch = ‘a’;

    Char *cp = &ch;

  示意图要求1. 标出求值的顺序,2中间专题是虚线,椭圆,方框

   表达式

     &ch

 cp

&cp

*cp

*cp+1

*(cp+1)

++cp

Cp++

*++cp

*cp++

++*cp

(*cp)++

++*++cp

++*cp++

实例,strlen.c 必会默写

指针+/- 整数  在什么情况下可以这样?

只能用于指向数组中某个元素的指针,也适用于使用malloc函数动态分配获得的内存。

指针指向数组最后一个元素的后面的那个内存位置,有什么问题?允许这样,一般不允许对指向这个位置的指针进行间接访问。

指针-指针什么情况下允许这样?

只有两个指针指向同一个数组中的元素时,相减的结果是ptrdiff_t(有符号整数类型)

<  <=   >  >= 可以比较的两个指针有什么限制?

他们都指向同一个数组中的元素,但是两个任意的指针可以执行相等或不相等测试。

数组

数组和指针的区别与联系?

数组和指针有着本质的不同,指针是一个标量值。数组名却有很多属性如:数组元素的数量。只有当数组名在表达式中使用时,编译器才会为它产生一个指针常量

先来搞明白,什么是声明,什么是定义?

c 语言中的对象有且只有一个定义,但它可以有多个extern 声明。这里的对象,只是跟链接器有关的“东西”比如函数和变量。

定义只能出现一个地方,声明可以出现多次,声明相当于普通的声明,它说明并非本身,而是描述其他地方创建的对象。定义相当于特殊的声明,它为对象分配内存

左值在编译时可知,左值标示存储结果的地方。右值直到运行时才知,如无特殊说明,右值表示的内容。

           C语言中有“可修改的左值”,很奇怪!意味着还有不可可以修改的左值,这个奇怪的术语是为与数组名(是左值)区分。

数组和指针是如何访问的?

char a[9] = “abcdefgh”;    …..   c= a[i];

编译器符号表具有一个地址9980

           运行时步骤1: 取i的值,将它与9980相加

           运行时步骤2: 取地址(9980+i)的内容

char *p ;  ………     c= *p;

编译符号表有一个符号p, 它的地址为4624;

         运行时步骤1: 取4624的内容,就是5081

           运行时步骤2: 取地址5081 的内容

指定的访问要灵活得多,但需要增加一次额外的提取。

 

定义为指针,但以数组方式引用时会发生什么?

  指针当然可以p[i] 用,

   char *p = “abcdefgh”;         c=p[i];

   编译器符号表具有一个p, 地址为4624

       运行步骤1 :取地址4624的内容,即5081,

                     运行步骤2:     取得i的值,并将它与5081相加

                     运行步骤3:     取得地址[ 5081 + i] 的内容

指定的访问要灵活得多,但需要增加一次额外的提取。(和数组a对比)

注意写代码时,声明与定义相匹配

 

指针

数组

通常用于动态数据结构

通常用于存储固定数目且数据类型相同的元素

相关的函数malloc(), free().

隐式分配和删除

通常指向匿名数据

自身即为数据名

间接访问

直接访问

 

 

定义指针时,编译器并不为指针指向的对象分配空间,它只是分配指针本身的空间,除非在定义时同时赋给指针一个字符串常量进行初始化。如:

char *p = “break”;

float *pip = 3.14;  //错误!!!!

什么时候数组和指针相同?

 数组声明,包含三种

  1. extern , 如  extern char a[]  ;  不能改写成指针的形式
  2. 定义,如  char  a[10];  不能改写成指针的形式
  3. 函数的参数,如func(char a[]);  选择数组形式,或者指针形式

  数组,在表达式中使用

                     如c = a[i];  选择数组形式  或指针形式

 

规则1: 表达式中的数组名被编译器当作一个指向该数组第一个元素的指针。

  例外情况如:  a 数组作为sizeof()的操作数;b 使用& 操作符取数组的地址;c数组是一个字符串,常量初始值。???

           如:

           int a[10], i=2;

           a[i]; 相当于*(a+i);  *(i+a);i[a]; 2[a];

           规则2: 在函数参数的声明中,数组名被编译器当作指向该数组第一个元素的指针。

           规则3: 下标总是与指针的偏移量相同

                     事实上,下标范围检查被认为并不值得加入C语言中。

指针总是有类型限制?p+2p+i   ; 是的,因为编译器要直到步长啊。

数组行参是如何被引用的?

 

猜你喜欢

转载自blog.csdn.net/u013862108/article/details/83933394