指针——小甲鱼

01

  1. 内存区的每一个字节有一个编号,这就是“地址”。如果在程序中定义了一个变量,在对程序进行编译时,系统就会给这个变量分配内存单元。
  2. 在c语言中,对变量的访问有两种方式,直接访问和间接访问。

直接访问如:a=5;

系统在编译时,已经对变量分配了地址,例如,若变量a分配的地址是2000,则该语句的作用就是把常数5保存到地址为2000的单元。

间接访问如:scanf(“%d”,&a);

调用函数,把变量a的地址传递给函数scanf,函数首先把该地址保存到一个单元中,然后把从键盘接收的数据通过所存储的地址保存到a变量中。

  1. 在c语言中,指针是一种特殊的变量,它是存放地址的。假设我们定义了一个指针变量int *i_pointer用来存放整型变量i的地址,则有:i_pointer=&i。
  2. 将i的地址(2000)存放到i_pointer中。这时,i_pointer的值就是(2000)。即变量i所占用单元的起始地址。要存取变量i的值,可以采用间接方式:先找到存放“i的地址”的变量i_pointer,从中取出i的地址(2000),然后取出i的值3。

指针——小甲鱼

  1. *:取值操作符,指针定义符。

&:取址操作符。

int i = 2000; //假设i的地址为1000h

int *pointer;

pointer = &i; //pointer=1000h

printf(“%d\n”,*pointer); //输出2000

  1. 知道了一个变量的地址,就可以通过这个地址来访问这个变量,因此,又把变量的地址称为该变量的“指针”。
  2. c语言中可以定义一类特殊的变量,这些变量专门用来存放变量的地址,成为指针变量。

注:指针变量的值(即指针变量中存放的值)是地址(即指针)。

  1. 定义指针变量:指针变量前面的“*”,表示该变量的类型为指针型变量。其一般形式为:类型说明符 *变量名; 其中,“*”表明这是一个指针变量,变量名即为定义的指针变量名,类型说明符表示本指针变量所指向的变量的数据类型。例如:

float *pointer;指针变量名是pointer。

  1. 只有整型变量的地址才能放到指向整型变量的指针变量中。
  2. 指针变量中只能存放地址(指针)。

 

 

 

 

 

02

  1. 如果已执行了语句:pointer_1=&a;
  1. &*pointer_1的含义是什么?

答:&和*两个运算符的优先级相同,但按自右向左方向结合,因此先进行*pointer_1的运算,它就是变量a,再执行&运算。因此,&*pointer_1与&a相同,即变量a的地址。

如果有:pointer_2=&*pointer_1; 它的作用就是将&a(a的地址)赋给pointer_2。

  1. *&a:先进行&a运算,得a的地址,再进行*运算。即a所指向的变量,也就是变量a。

*&a和*pointer_1的作用是相同的,它们都等价于变量a。即*&a与a等价。

  1. (*pointer_1)++相当于a++
  1. 数组:一个变量有地址,一个数组包含若干个元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。
  2. 指针变量可以指向变量,当然也可以指向数组元素(把某一元素的地址放到一个指针变量中)。
  3. 数组元素的指针就是数组元素的地址。
  4. 定义一个指向数据元素的指针变量的方法,与指向变量的指针变量相同。
  5. 引用一个数组元素,可以用:(1)下标法,如a[i]形式
  1. 指针法,如*(a+1)或*(p+1)

其中的a是数组名,p是指向数组元素的指针变量,其初值p==a(p==&a[0])。数组名即数组的第一个元素的地址。

注:在指针法中,*(a+i)表示指向的是第i个元素,而不是加了多少个地址。

 

 

 

 

 

 

 

 

 

 

03

  1. int arr[]:在编译时是将arr按指针变量处理的,即

f(int arr[],int n)相当于f(int *arr,int n)

2、c语言调用函数时,当用变量名作为函数参数时,传递的是变量的值,当用数组名作为函数参数时,由于数组名代表的是数组首元素地址。因此传递的值是地址,所以要求形参为指针变量。

 

 

 

 

 

 

 

04

  1. 如果有一个实参数组,想在函数中改变此数组中的元素的值,实参与形参的对应关系有以下4种情况:
  1. 形参和实参都用数组名:

void main(){

int a[10];

f(a,10);

}

void f(int x[],int n){
    ...

}

  1. 实参用数组名,形参用指针变量:

void main(){

int a[10];

f(a,10);

}

void f(int *a,int n){
    ...

}

  1. 实参形参都用指针变量:

void main(){

int a[10],*p=a;

f(p,10);

}

void f(int *x,int n){
    ...

}

  1. 实参为指针变量,形参为数组名:

void main(){

int a[10],*p=a;

f(p,10);

}

void f(int x[],int n){
    ...

}

 

  1. 可以认为二维数组是“数组的数组”,例:

int a[3][4]={{1,3,5,7},{},{}};

则二维数组a是由3个一维数组所组成的。

设该二维数组的首行的首地址为2000,则有:

第一行地址a[0]

2000

a[0][0]

2004

a[0][1]

2008

a[0][2]

2012

a[0][3]

存放数据

1

3

5

7

第二行地址

a[1]

2016

a[1][0]

2020

a[1][1]

2024

a[1][2]

2028

a[1][3]

存放数据

9

11

13

15

第三行地址

a[2]

2032

a[2][0]

2036

a[2][1]

2040

a[2][2]

2044

a[2][3]

存放数据

17

19

21

23

 

 

 

 

表示形式

含义

地址

a

二维数组名,指向一位数组a[0],即0行首地址。

2000

a[0]

*(a+0)

*a

0行0列元素地址

2000

a+1

&a[1]

1行首地址

2016

a[1]

*(a+1)

1行0列元素a[1][0]的地址

2016

a[1]+2

*(a+1)+2

&a[1][2]

1行2列元素a[1][2]的地址

2024

*(a[1]+2)

*(*(a+1)+2)

a[1][2]

1行2列元素a[1][2]的值

元素值为13

 

  1. 把二维数组a分解为一维数组a[0]、a[1]、a[2]之后,设p为指向二维数组的指针变量,可定义为:int  (*p)[4]。它表示p是一个指针变量,它指向包含4个元素的一维数组。若指向第一个一维数组a[0],其值等于a、a[0]或&a[0][0]等。而p+i则指向一维数组a[i]。
  2. 从前面的分析可得出*(p+i)+j是二维数组i行j列的元素的地址,而*(*(p+i)+j)则是i行j列元素的值。(先取出第i个一维数组,再取出一维数组中的第j个元素)
  3. 二维数组指针变量说明的一般形式为:

类型说明符 (*指针变量名)[长度]

其中,类型说明符为所指数组的数据类型。“*”表示其后的变量是指针变量。“长度”表示二维数组分解为多个一维数组时,一维数组的长度,也就是二维数组的列数。

注:要为指针变量赋初值。

 

 

 

 

 

05

字符串与指针

无笔记

 

 

 

 

06

在c/c+中,内存分成5个区,它们分别是堆、栈、*存储区、全局/静态存储区和常量存储区。

栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区,里面的变量通常是局部变量、函数参数等。

堆,就是那些由new分配的内存块,它们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。

*存储区,就是那些由malloc等分配的内存块,它和堆是十分相似的,不过它是用free来结束自己的生命的。

全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的c语言中,全局变量又分为初始化的和未初始化的,在c++里面没有这个区分了,它们共同占用同一块内存区。

常量存储区,这是一块比较特殊的存储区,它们里面存放的是常量,不允许修改(当然,通过非正当手段也可以修改,而且方法很多)

 

 

 

 

07

1、字符数组和字符指针变量的区别:

1>字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址(字符串第一个字符的地址),而不是将字符串放到字符指针变量中。

2>赋值方式。对字符数组只能对各个元素赋值,不能用以下办法对字符数组赋值:

char str[20];

str = “just do it!”;

而对字符指针变量,可以采用下面的方法赋值:
char *a;

a = “just do it!”;

注意赋给a的不是字符串,而是字符串第一个元素的地址。

3>对字符指针变量赋初值:
char *a=”just do it!”; 等价于char *a; a = “just do it!”;

而对数组的初始化:

char str[20]=”just do it!”; 不能等价于

char str[20]; str[]=”just do it!”;

4>如果定义了一个字符数组,在编译时为它分配内存单元,它有确定的地址。而定义一个字符指针变量时,给指针变量分配内存单元,在其中可以放一个字符变量的地址。也就是说,该指针变量可以指向一个字符型数据,但如果未对它赋予一个地址值,则它并未具体指向一个确定的字符数据。

5>指针变量的值是可以改变的。

6>若定义了一个指针变量,并使它指向一个字符串,就可以用下标形式引用指针变量所指的字符串中的字符。

2、一个函数在编译时就分配给一个入口地址。这个函数的入口地址就成为函数的指针。

3、做注释:#if(1/0) #endif

4、函数指针变量常用的用途之一是把指针作为参数传递到其他函数。指向函数的指针也可以作为参数,以实现函数地址的传递,这样就能够在被调用的函数中使用实参函数。

指针——小甲鱼

  1. 格式:
    函数指针变量的声明格式:

返回类型 (*函数指针变量)(参数列表)

调用格式:(*函数指针变量)(实参列表)

 

 

08

  1. 一个函数可以带回指针型的数据,即地址。

形式为:类型名 *函数名(参数列表)

int *a(int x,int y);

  1. 指针函数是指带指针的函数,即本质是一个函数。
  2. 函数指针是指向函数的指针变量,因而函数指针本身首先应是指针变量,只不过该指针变量指向函数。
  3. 指针数组:一个数组,若其元素均为指针类型数据,称为指针数组,也就是说,指针数组中的每一个元素都相当于一个指针变量。

类型名 *数组名[数组长度];

int *name[4];

  1. 指向指针的指针:定义一个指向指针数据的指针变量,形式如:char **p; p的前面有两个*号。*运算符的结合性从右到左,因此**p相当于*(*p),显然*p是指针变量的定义形式。如果没有最前面的*,那就是定义了一个指向字符数据的指针变量。现在它前面又有一个*号,表示指针变量p是指向一个字符指针变量的。*p就是p所指向的另一个指针变量。
  2. 指针数组的一个重要应用是作为main函数的形参。在以往的程序中,main函数的第一行一般写成以下形式:void main();

括号中是空的。实际上,main函数可以有参数:

void main(int argc,char *argv[]); argc和argv就是main函数的形参。

  1. main函数是由操作系统调用的。那么,main函数的形参的值从哪里来?显然不是在程序中得到。实际上,实参是和命令一起给出的。也就是在一个命令行中包括命令名和需要传递给main函数的参数。

 

 

 

 

 

09

1、

定义

含义

int i;

定义整型变量i

int *p;

p为指向整型数据的指针变量

int a[n];

定义整型数组a,它有n个元素

int *p[n];

定义指针数组p,它由n个指向整型数据的指针元素组成

int (*p)[n];

p为指向含n个元素的一维数组的指针变量

int f();

f为带回整型函数值的函数

int *p();

p为带回一个指针的函数,该指针指向整型数据

int (*p)();

p为指向函数的指针,该函数返回一个函数值

int **p;

p是一个指针变量,它指向一个指向整型数据的指针变量

  1. 指针变量加(减)一个整数:p++、p--、p+i、p-i、p+=i、p-=i等。
  2. 指针变量赋值:将一个变量地址赋给一个指针变量。如:

p=&a;(将变量a的地址赋给p)

p=array;(将数组array首元素地址赋给p)

p=&array[i];(将数组array第i个元素的地址赋给p)

p=max;(max为已定义的函数,将max的入口地址赋给p)

p1=p2;(p1和p2都是指针变量,将p2的值赋给p1

指针变量可以有空值,即该指针变量不指向任何变量,可以这样表示:p=NULL;

  1. 两个指针变量可以相减。相减的结果是地址在内存空间中相差的指针类型的字节倍数。
  2. 两个指针变量比较:若两个指针指向同一个数组元素,则可以进行比较。指向前面的元素的指针变量“小于”指向后面元素的指针变量。
  3. void真正发挥的作用在于:(1)对函数返回的限定(2)对函数参数的限定。 例:void abc(void);
  4. ANSI C新标准增加了一种“void”指针类型,即不指定它是指向哪一种类型数据的指针变量。

例如:void *p; 表示指针变量p不指向一个确定的类型数据,它的作用仅仅是用来存放一个地址。

  1. void指针它可以指向任何类型数据。也就是说,可以用任何数据类型的指针直接给void指针赋值。但是,如果需要将void指针的值赋给其他类型的指针,则需要进行强制类型转换。