C语言---指针

C语言中对变量的访问有两种方式:

1)直接访问,通过变量名;

2)间接访问,通过地址来访问某一个变量,该变量的地址是另一个变量的内容。

事实上,程序经过编译后,对变量的访问都会变为从地址的访问。

printf("%d \n", i);

scanf("%d \n", &i);   //scanf语句使用&i来访问

 

一个变量的地址称为该变量的指针,地址被形象的称为指针,如果一个变量专门用来存放另一变量的地址,它被称为

"指针变量",指针变量的值---是另一个变量的地址,指针变量的地址---是本身变量的地址。

 

定义指针变量:

类型名   *指针变量名;

int *point_1;

int *point_2 = &b; //定义时,初始化

指针变量名前的"*"表示变量为指针变量,point_1的值表示另一变量的地址,*point_1表示另一变量的值

                                                        &point_1表示该指针变量的地址

定义指针变量时,必须制定基类型,因为访问一个变量不但需要知道首地址,还需要知道访问的字节数。

&取地址运算符; *指针运算符

 

指针在调用指针运算符,对另一变量赋值的时候,必须先对指针的值进行初始化,否则,指针指向的地址未知,容易发生错误。

int * temp;

*temp = *p1;   //容易产生错误

 

当指针变量作为函数参数时,它表示将一个变量的地址传送给另一变量。 

void swap(int *ptr1, int *ptr2) {

  int *temp;

  temp = *ptr1;           //输入指针交互各自内容,temp可以定义为普通int变量

  *ptr1 = *ptr2;

  *ptr2 = temp;

}

void swap(int *ptr1, int *ptr2) {

  int *temp;

  temp = ptr1;        //输入指针各自指向的地址交换

  ptr1 = ptr2;

  ptr2 = temp;

}

数组名作为函数的实参传递时,也是表示指针的传递。

void main () {

fun(array,10);

}

void fun(int arr[], int n) {

}

实参用指针、数组表示,形参用数组、指针表示都是等价的。

 

通过指针引用数组。数组本身也是一种特殊的指针:

  int a[10];

  int *ptr;

  ptr = &a[0];  //C语言中数组a[10]的地址,可以用&a[0]或者a来访问

  ptr = a;  //与&a[0]等价

数组元素的引用:

下标: a[i];

指针:*(a+i)

*(p++),表示先取*p的值,然后p自加1;

*(++p),表示p先自加1,然后再取*p的值;

 

C语言中,字符串是存放在字符数组中的,有两种表示方法:

1) 用字符数组存放一个字符串,通过数组下标引用某个字符,%s+数组名输出整个字符串,%c+数组下标输出某个字符

   char string[] = "I am a big man"

   printf("%s\n",string);

   printf("%c\n",string[4]);   //最后一个字符存放"\0"

2) 用指针变量指向一个字符串常量

   char *string = "I am a big man"

   等价于 char *string;  string = "I am a big man"   //对字符指针的访问不需要加"*"

 

指向函数的指针,系统编译的时候,编译系统会为子函数代码分配一段存储空间,这段存储空间的起始地址称为这个函数的指针。

int (*p) (int,int)表示指向一个返回值为int,且有两个int 参数的函数。

所以函数的调用可以使用函数名直接调用,也可以通过函数指针来调用。

int main() {

  int max(int, int);    //函数声明

  int (*p)(int, int);     //函数指针声明

  int a,b;

  p = max;  //使得P指向max函数

  c = (*p) (a,b);  //通过函数指针调用函数

}

 

返回指针的函数定义:  类型名  *函数名(参数列表)

float *search (float *point, int b)   //返回值为float *类型的指针

指针数组:一个数组,其中的每个值都是指针变量,类型名 *数组名[数组长度]

int *p[4];  //[]优先级比*高,所以先形成p[4]形式,后加*p

int (*p)[4];  //表示指向一维数组的变量

 

动态分配内存空间,

void  *malloc(unsigned int size);  //分配大小为size字节的连续空间,赋值时,最好强制转换指针类型。

void  *calloc(unsigned n, unsigned int size);  //分配n个连续的size字节大小的连续空间,赋值时,最好进行强制类型转换。

void  *free(void *p);  //释放指针p指向的已分配的动态空间。

void  *realloc(void *p, unsigned int size);  //已分配过的地址,重新改变其大小。将p指向的地址,改为size大小。

 

将void类型的指针赋值给不同的基类型的指针变量时,不需要用户进行强制类型转换,编译系统会自动进行转换。

 

链表是一种常见的动态分配内存的结构。

链表由很多节点组成,每个节点,包括两部分,1)用户实际的存储数据,2)下一个节点的地址。

链表都有一个头指针,"head",只存放一个地址,指向下一个数据元素。最后一个节点的地址指向null

使用结构体来建立链表是比较合适的。

struct Student {int num;

                       float score;

                       struct Student *next;}

 

静态链表的建立:   //静态链表,存储空间在编译时,已经是定死的

struct Student a,b,c,*head,*p

head = &a;

a.next = &b;

b.next = &c;

c.next = null;

动态链表的建立:

struct Student * creat(void)  {  //返回一个指向struct Student类型的指针

 struct  Student  * head;

 struct  Student *p1, *p2;

 n = 0;

 p1 = p2 =(struct Student *) malloc(LEN);

 scanf("%ld, %f", &p1->num, &p2->score);   //输入第一个同学的分数

 while(p1->num != 0)  {           //直到输入的num为0,停止

  n = n+1;

  if(n==1) head = p1;

  else p2->next = p1;   //p2中指向的是,新的内存空间的入口

  p2 = p1;   //p2被赋值为p1   //将p2表示为上一次的节点地址。

  p1 = (struct Student *) malloc(len);  //p1是每次重新分配的内存入口

  scanf("%ld, %f", &p1->num, &p2->score);   //输入下一个同学的分数

  }

 

数组指针与指针数组,[]的优先级高于*(p);

数组指针:int (*p)[n],也称为指向一维数组的指针,

  int (*p)[4];定义一个数组指针,指向含4个元素的一维数组,每次加一,是增加4个byte。

  int a[3][4];

  p = a;

  p++,该语句执行结束之后,p=p+1,p直接指向a[1][0]

指针数组:int *p[n],本身也是一个数组,但是数组中的数据,都是指针,

  赋值的时候,需要注意,*(p[n]) = num,作为指针进行赋值。

 

数组指针,只是一个特殊的指针,专门用来指向一个二维数组,

指针数组,是一个指针的list,多个指针,连续的存放在内存中。

posted @ 2017-04-04 15:05  _9_8  阅读(438)  评论(0编辑  收藏  举报