C语言指针解析

C语言编译参考博文:C及C++源码执行流程及编译

1 小解

C语言一大特色-指针,指针(pointer)是变量的地址。
指针变量是存放地址的变量。因此,正确灵活使用指针可有效表示复杂的数据结构,动态分配内存。

2 例解

2.1 指针变量的引用

  • Demo1
# include<stdio.h>
void main() {
	// 整型变量
	int a=250,i=250,j=2500;
	// 整型指针变量
	int *p1,*p_1, *p_2;
	// 指针变量名赋值
	p_1 = &i;
	p_2 = &j;
	printf("%s %d, %d \n", "直接访问:",i ,j);
	printf("%s %d, %d \n", "指针访问:", *p_1, *p_2);
	printf("%s %p, %p \n","变量地址:", p_1, p_2);
}
  • Result
直接访问: 250, 2500 
指针访问: 250, 2500 
变量地址: -531005380, -531005384 
  • Analysis
    (1) 定义指针变量使用星号*,且需要指定指针变量的类型,即存储的地址类型,若存储整型变量的地址,则使用int *p_1;表示,其他类推;
    (2) 指针变量的赋值,使用指针变量名赋值,指针变量名为p_1,不包括星号,星号表示取指针指向的对象的内容,即指针变量*p_1指向存储单元&i的内容;变量名表示地址值,如上*p_1输出变量值,p_1输出变量地址;
    (3) 指针变量只能接受地址;
    (4) &取变量地址,*取指针所指对象的内容(值);

在这里插入图片描述

图2.0 指针变量与常规变量

2.2 交换地址比较数据大小

  • Demo2
# include<stdio.h>
void main() {
	int a, b, *p1, *p2;
	scanf("a=%d, b=%d", &a, &b);
	p1 = &a, p2 = &b;
	if (a<b) {
		p1 = &b;
		p2 = &a;
	}
	printf("输入原始值:a=%d, b=%d \n", a, b);
	printf("比较值:max=%d, min=%d \n", *p1, *p2);
}
  • Result
a=250,b=2500
输入原始值:a=250, b=2500 
比较值:max=2500, min=250
  • Analysis
    (1) 比较a和b的值,使用指针操作,通过改变指向的地址,即可改变输出值;保证原值不变;
    (2) 交换值:指针通过交换地址,普通变量需要通过中间变量改变值;

2.3 指针变量作为函数参数数字比较

  • Demo3
# include<stdio.h>
void pointer_swap_value(int *p1, int *p2) {
	int temp;
	temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}

void pointer_swap_address(int *p3, int *p4) {
	int *temp1;
	temp1 = p3;
	p3 = p4;
	p4 = temp1;
}

void normal_swap(int x, int y) {
	int temp2;
	temp2 = x;
	x = y;
	y = temp2;
}

void main() {
	void pointer_swap_value(int *p1, int *p2);
	void pointer_swap_address(int *p3, int *p4);
	void normal_swap(int x, int y);
	int a, b, c, d,e,f;
	int *pointer_1, *pointer_2, *pointer_3, *pointer_4;
	scanf("a=%d,b=%d,c=%d,d=%d,e=%d,f=%d",&a, &b, &c, &d, &e, &f);
	pointer_1 = &a;
	pointer_2 = &b;
	pointer_3 = &e;
	pointer_4 = &f;
	
	if (a<b) {
		pointer_swap_value(pointer_1, pointer_2);
	}
	if (c<d) {
		normal_swap(c, d);
	}
	if (e<f) {
		pointer_swap_address(pointer_3, pointer_4);
	}
	printf("指针交换值比较结果:a=%d, b=%d\n", a, b);
	printf("普通比较结果:c=%d, d=%d \n", c, d);
	printf("指针交换地址比较结果:e=%d, f=%d \n", e, f);
}
  • Result
a=250,b=2500,c=250,d=2500,e=250,f=2500
指针交换值比较结果:a=2500, b=250
普通比较结果:c=250, d=2500 
指针交换地址比较结果:e=250, f=2500
  • Analysis
    (1) 普通函数调用normal_swap实参将数据传递给形参,形参交换数据后,形参被释放,实参的值并未改变;
    (2) 指针地址进行实参和形参的值传递,同样,当调用结束后,地址被释放,实参仍不能改变;
    (3) 通过改变实参变量指向的变量内容,可实现实参数据的改变;

比较前各指针和变量对应关系:

在这里插入图片描述

图2.1 初始化对应关系

初始化时, 实际变量a,b地址假设为0x001,0x002,指向他们的指针分别指向对应的地址,形参对应的地址如上图所示,只有变量的形参地址有所出入(为方便理解,这里仍用a,b变量表示),因为形参是新开辟的地址,但是指针形参具有指向性,所以地址仍是实参的地址.

在这里插入图片描述

图2.2 交换后对应关系

执行交换操作时,使用指针变量作为形参的交换有两种交换方式,一种是交换指针变量的值,一种是交换指针变量指向的地址,若交换指针变量的值,则改变形参的值,此时实参的指针也是指向该形参的地址,所以当形参释放是改变了实参的值;若交换指针地址,则将形参指针指向不同的地址,没有改变地址中的内容,所以形参释放时,实参值不会改变;而直接传递变量时,则出现更扯的情况,因为地址都不一样,释放后,自然不会改变实参.

2.4 指针与数组

2.4.1 一维数组

在这里插入图片描述

图2.3 指针与一维数组
  • Demo
# include<stdio.h>
void main() {
	int a[10], i=250, j;
	int *p, *p1=&i;
	p = a;
	for(j=0;j<10;j++) {
		a[j] = j;
	}
	for(p=a;p<(a+10);p++) {
		printf("pointer to array: %d \n",*p);
	}
	printf("pointer: %d \n", *p1);
}
  • Result
pointer to array: 0 
pointer to array: 1 
pointer to array: 2 
pointer to array: 3 
pointer to array: 4 
pointer to array: 5 
pointer to array: 6 
pointer to array: 7 
pointer to array: 8 
pointer to array: 9 
pointer: 250
  • Analysis
    (1) 数组名为数组首地址,p=a即将指针指向数组首地址,首地址为常量,所以索引数组时使用p++自增;
    (2) 指针索引数组元素:p+j;
    (3) 指针赋值:int *p=&i;p=&i;

2.4.2 二维数组

在这里插入图片描述

图2.4 二维数组与指针
  • Demo
#include <stdio.h>
#include <stdlib.h>

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[]) {
	float (*p)[3],*p1,*p2;
	int i, j, row, column, ele_num;
	void line_split();
	float score[4][3] = {{10, 20, 30},{40, 50, 60},{70, 80, 90},{100, 110, 120}};
	row = sizeof(score)/sizeof(score[0]);
	column = sizeof(score[0])/sizeof(score[0][0]);
	ele_num = row * column;
	printf("Array row: %d,column:%d\n",sizeof(score)/sizeof(score[0]),sizeof(score[0])/sizeof(score[0][0]));
	line_split();
	/*Array score address.*/
	printf("score[i]+j address.\n");
	for(i=0;i<4;i++){
		for(j=0;j<3;j++){
			printf("%p\t",score[i]+j); 
		}
		printf("\n");
	}
	line_split();
	/*Assign array name to pointer.*/
	printf("p+n address.\n");
	for(p1=score[0];p1<score[0]+ele_num;p1++){
		if((p1-score[0])%3==0) printf("\n");
		printf("%p\t",p1);
	}
	printf("\n");
	
	line_split();
	/*Array row get initial address.*/
	printf("Row first element address.\n");
	printf("&score[0][0]:%p\tscore[0]:%p\t&score[0]:%p\tscore:%p\t*(score):%p\n",&score[0][0] ,score[0], &score[0],*score, score);
	printf("&score[1][0]:%p\tscore[1]:%p\t&score[1]:%p\t(score+1):%p\t*(score+1):%p\n",&score[1][0] ,score[1], &score[1], score+1, *(score+1));
	printf("&score[2][0]:%p\tscore[2]:%p\t&score[2]:%p\t(score+2):%p\t*(score+2):%p\n",&score[2][0] ,score[2], &score[2], score+2, *(score+2));
	printf("&score[3][0]:%p\tscore[3]:%p\t&score[3]:%p\t(score+3):%p\t*(score+3):%p\n",&score[2][0] ,score[3], &score[3], score+3, *(score+3));
	line_split();
	printf("%p\n",score[0]+4);
	line_split();
	printf("*(score+i)+j address\n");
	for(i=0;i<4;i++){
		for(j=0;j<3;j++){
			printf("%p\t",*(score+i)+j);
		}
		printf("\n"); 
	}
	line_split();
	printf("%f\n", *(p1+9));
	p = score;
	printf("%f", *(*(p+3)+2));
	
	system("pause");
}
void line_split(){
	printf("-------------------\n");
}

  • Result
Array row: 4,column:3
-------------------
score[i]+j address.
000000000062FDE0        000000000062FDE4        000000000062FDE8
000000000062FDEC        000000000062FDF0        000000000062FDF4
000000000062FDF8        000000000062FDFC        000000000062FE00
000000000062FE04        000000000062FE08        000000000062FE0C
-------------------
p+n address.

000000000062FDE0        000000000062FDE4        000000000062FDE8
000000000062FDEC        000000000062FDF0        000000000062FDF4
000000000062FDF8        000000000062FDFC        000000000062FE00
000000000062FE04        000000000062FE08        000000000062FE0C
-------------------
Row first element address.
&score[0][0]:000000000062FDE0   score[0]:000000000062FDE0       &score[0]:000000000062FDE0      score:000000000062FDE0
*(score):000000000062FDE0
&score[1][0]:000000000062FDEC   score[1]:000000000062FDEC       &score[1]:000000000062FDEC      (score+1):000000000062FDEC      *(score+1):000000000062FDEC
&score[2][0]:000000000062FDF8   score[2]:000000000062FDF8       &score[2]:000000000062FDF8      (score+2):000000000062FDF8      *(score+2):000000000062FDF8
&score[3][0]:000000000062FDF8   score[3]:000000000062FE04       &score[3]:000000000062FE04      (score+3):000000000062FE04      *(score+3):000000000062FE04
-------------------
000000000062FDF0
-------------------
*(score+i)+j address
000000000062FDE0        000000000062FDE4        000000000062FDE8
000000000062FDEC        000000000062FDF0        000000000062FDF4
000000000062FDF8        000000000062FDFC        000000000062FE00
000000000062FE04        000000000062FE08        000000000062FE0C
-------------------
  • Analysis
    (1) score和score[0]+0表示二维数组的第0行第0列的地址,其他元素依次类推score[0]+n;&score[0][0]表示第0行第0列元素地址;
    (2) score[0]+1表示第0行第1列元素地址;score[1]+2表示第一行第二列元素地址;
    (3) score+1表示第1行第0列元素地址;
    (4) 普通指针变量p指向数组,每次偏移一个单位指向下一个元素,不能跨行偏移;
    (5) 地址获取后,可直接使用*获取地址内的值;

数组元素对应地址表示:

序号012
0&score[0][0]&score[0][1]&score[0][2]
score[0]score[0]+1score[0]+2
&score[0]*(score+0)+1*(score+0)+2
score
*score
1&score[1][0]&score[1][1]&score[1][2]
score[0]+3score[0]+4score[0]+5
score[1]score[1]+1score[1]+2
&score[1]*(score+1)+1*(score+1)+2
score+1
*(score+1)
2&score[2][0]&score[2][1]&score[2][2]
score[0]+6score[0]+7score[0]+8
score[2]score[2]+1score[2]+2
&score[2]*(score+2)+1*(score+2)+2
score+2
*(score+2)
3&score[3][0]&score[3][1]&score[3][2]
score[0]+9score[0]+10score[0]+11
score[3]score[3]+1score[3]+2
&score[3]*(score+3)+1*(score+3)+2
score+3
*(score+3)

指针表示地址:p=score[0];

序号012
0pp+1p+2
1p+3p+4p+5
2p+6p+7p+8
3p+9p+10p+11

2.4.3 数组指针

指向一维数组的指针变量,表示行指针,指向二维数组的行,实实在在的指针,(*p)[n]数据n表示列数,结构如下图:
格式:

int (*p)[3];

在这里插入图片描述

图2.5 数组指针示意图

其中,(*p)[3]表示指向的行有3个元素,指向的行数不限。

  • Demo1
#include <stdio.h>
#include <stdlib.h>

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[]) {
	float (*p)[3],*p1,*p2;
	int i, j, row, column, ele_num, c, r;
	void line_split();
	float score[4][3] = {{10, 20, 30},{40, 50, 60},{70, 80, 90},{100, 110, 120}};
	/*返回指针的函数*/
	float *search_column(float (*pointer_c)[3], int column);
	float *p_c, *p_r;
	printf("Enter the number of student:");
	scanf("%d,%d", &c,&r);
	printf("The score of No.%d are:\n", c);
	p_c = search_column(score, c);
	for(i=0;i<3;i++){
		printf("%5.2f\t", *(p_c+i));
	} 
	system("pause");
//	return 0;
}

float *search_column(float(*pointer_c)[3], int column){
	float *pt;
	pt = *(pointer_c+column);
	return(pt);
}
  • Result
Enter the number of student:2
The score of No.2 are:
70.00   80.00   90.00
  • Analysis
    (1) 指针变量*p指向一维数组,(p)[3]该数组含有3个浮点型元素;
    (2) p表示二维数组中的行(p=score),取元素地址:
    (p+i)+j;

  • Demo2

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

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[]) {
	int i, j;
	int a[3][2] = {{10, 11}, {2, 13}, {3, 14}};
	int a1[4][3] = {{2, 3, 5}, {6, 5, 5}, {44, 20, 30}, {55, 22, 33}};
	int (*p2)[2], *p3, (*p4)[2];
	printf("\n------数组指针:行指针------\n");
	p4 = a1;
	for(i=0;i<3;i++){
		// p4表示行指针,列数为2:(*p4)[2] 
		printf("取数组指针的值:%d\n", *p4[i]);
	}
	
	printf("\n------数组指针:默认方式------\n");
	// 数组指针相当于二维数组的行指针 
	p2 = a;
	for(i=0;i<3;i++){
		for(j=0;j<2;j++){
			printf("%d\t", &a[i][j]);
		}
	}

	printf("\n");
	for(i=0;i<6;i++){
		printf("%d\t", *(p2)+i);
	}
	printf("\n");
	for(i=0;i<3;i++){
		for(j=0;j<2;j++){
			printf("%d\t", a[i][j]);
		}
	}
	printf("\n");
	for(i=0;i<6;i++){
		printf("%d\t", *(*p2+i));
	}
	
	printf("\n------数组指针:指定方式1------\n");
	(*p2)[0] = a[0][0];
	for(i=0;i<3;i++){
		for(j=0;j<2;j++){
			printf("%d\t", &a[i][j]);
		}
	}

	printf("\n");
	for(i=0;i<6;i++){
		printf("%d\t", p2[0]+i);
	}
	printf("\n");
	for(i=0;i<3;i++){
		for(j=0;j<2;j++){
			printf("%d\t", a[i][j]);
		}
	}
	printf("\n");
	for(i=0;i<6;i++){
		printf("%d\t", *(p2[0]+i));
	}

	printf("\n------数组指针:指定方式2------\n");
	p4 = a1; 
	
	for(i=0;i<4;i++){
		for(j=0;j<3;j++){
			printf("%d\t", &a1[i][j]);
		}
	}

	printf("\n");
	for(i=0;i<12;i++){
		printf("%d\t", *(p4)+i);
	}
	printf("\n");
	for(i=0;i<4;i++){
		for(j=0;j<3;j++){
			printf("%d\t", a1[i][j]);
		}
	}
	printf("\n");
	for(i=0;i<12;i++){
		printf("%d\t", *(*(p4)+i));
	}
	
	printf("\n----普通指针----\n"); 
	p3 = a;
	for(i=0;i<3;i++){
		for(j=0;j<2;j++){
			printf("%d\t", &a[i][j]);
		}
	}

	printf("\n");
	for(i=0;i<6;i++){
		printf("%d\t", p3+i);
	}
	printf("\n");
	for(i=0;i<3;i++){
		for(j=0;j<2;j++){
			printf("%d\t", a[i][j]);
		}
	}
	printf("\n");
	for(i=0;i<6;i++){
		printf("%d\t", *(p3+i));
	}
	
	system("pause");
	return 0;
}
  • Result
------数组指针:行指针------
取数组指针的值:2
取数组指针的值:5
取数组指针的值:5

------数组指针:默认方式------
6487408 6487412 6487416 6487420 6487424 6487428
6487408 6487412 6487416 6487420 6487424 6487428
10      11      2       13      3       14
10      11      2       13      3       14
------数组指针:指定方式1------
6487408 6487412 6487416 6487420 6487424 6487428
6487408 6487412 6487416 6487420 6487424 6487428
10      11      2       13      3       14
10      11      2       13      3       14
------数组指针:指定方式2------
6487360 6487364 6487368 6487372 6487376 6487380 6487384 6487388 6487392 6487396 6487400 6487404
6487360 6487364 6487368 6487372 6487376 6487380 6487384 6487388 6487392 6487396 6487400 6487404
2       3       5       6       5       5       44      20      30      55      22      33
2       3       5       6       5       5       44      20      30      55      22      33
----普通指针----
6487408 6487412 6487416 6487420 6487424 6487428
6487408 6487412 6487416 6487420 6487424 6487428
10      11      2       13      3       14
10      11      2       13      3       14
  • Analysis
    (1) 数组指针为行指针,等同二维数组的行,其中(*p4)[2],表示p4为数组指针,该指针指向的二维数组有两列;
    (2) p4等价于a1[x],表示行,*p4[i]隔一个数取值,表示两列元素;
    (3) *p4+i逐次取第i个元素的地址,*(*p4+i)依次取第i个元素的值;
    (4) 由分配的地址空间可知,每个整型数据,分配4个字节,如6487360 6487364分别表示a[0][0]a[0][1];

2.4.4 指针数组

指针数组用于表示二维数组,是二维数组的优化,仍是数组性质,只不过将数组的内容改为指针,用指针指向数据,节约内存,结构如图2.6所示:
格式:

type *point[number];

在这里插入图片描述

图2.6 指针数组示意图

其中,通过一位数组取值方式获取指针数组的值,取值格式:name[i],取地址name+i,&name[i],i为整数,若数组未赋值,指针数组为空指针(null)。

  • Demo
#include <stdio.h>
#include <stdlib.h>

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[]) {
	int i, j;
	int a[3][2] = {{10, 11}, {2, 13}, {3, 14}};
	int a1[4][3] = {{2, 3, 5}, {6, 5, 5}, {44, 20, 30}, {55, 22, 33}};
	int (*p2)[2], *p3, (*p4)[2];
	char *p5[10] = {"我爱我家", "我爱祖国", "热爱生活", "爱家人", "爱自己"};
	char temp, *p6, **p7;
	char a2[5][256] = {"我爱我家", "我爱祖国", "热爱生活", "爱家人", "爱自己"};
	printf("\n------字符串数组------\n");
	for(i=0;i<5;i++){
		printf("%s\t",a2[i]);
		p5[i] = a2[i];
		printf("%s\t", p5[i]);
	}
	printf("\n------指针数组------\n");
//	printf("指针数组:%s", p5[0]);
	for(i=0;i<10;i++){
		printf("%s\t", p5[i]);
	}
	printf("\n------指针的指针1------\n");
	temp = 'x';
	p6 = &temp;
//	printf("temp: %c", temp);
	p7 = &p6;
	printf("指针的指针: %c,%c,%c",temp, *p6, **p7);
	printf("\n------指针的指针2------\n");
	// 定义时初始化,字符串赋值 
//	char temp1[10]={"xin"};
	char temp1[10] = {'x', 'i', 'n'};
	p6 = temp1;
	p7 = &p6;
    printf("指针的指针: %c,%c,%c",temp1, *p6, **p7);
	printf("字符串数组:%s", temp1); 
	char temp2[10];
	// 单个元素字符赋值 
	temp2[0]='x';
	printf("字符数组: %s",temp2);
	
	printf("\n------指针数组------\n");
	
	system("pause");
	return 0;
}
  • Result
------字符串数组------
我爱我家        我爱我家        我爱祖国        我爱祖国        热爱生活        热爱生活        爱家人  爱家人  爱自己
爱自己
------指针数组------
我爱我家        我爱祖国        热爱生活        爱家人  爱自己  (null)  (null)  (null)  (null)  (null)
------指针的指针1------
指针的指针: x,x,x
------指针的指针2------
指针的指针: x,x,x字符串数组:xin字符数组: x
  • Analysis
    (1) 二维数组a2[5][256] = {“我爱我家”, “我爱祖国”, “热爱生活”, “爱家人”, “爱自己”};需要指定数组行空间和列空间,以满足存储,但是会造成内存浪费,5*256个字节中只有一小部分被实际使用,短字符串会让大部分的行是空的,另一方面,这个行根本没有使用到,却为他预留内存;
    (2) 指针数组就是来解决该问题的,*p[5]={“我爱我家”, “我爱祖国”, “热爱生活”, “爱家人”, “爱自己”};,此种方式,建立含有5个指针变量的数组,这些指针指向对应的数组元素,然后只给实际存在的对象分配内存未使用的则为空指针:null,结果:(null) (null) (null) (null) (null);
    (3) 空指针:null无值,但是分配地址,只是未指定是那个地址块,
    (3) 直接通过p[i]取值,因为指针已经指向了该数据,可直接获取;

2.4.5 指针的指针

该指针指向另一个指针,即存储另一个指针的地址,也称二级指针。
格式

type **pointer;

-Demo

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

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[]) {
	char temp, *p6, **p7;
	printf("\n------指针的指针1------\n");
	temp = 'x';
	p6 = &temp;
	p7 = &p6;
	printf("指针的指针: %c,%c,%c",temp, *p6, **p7);
	printf("\n------指针的指针2------\n");
	// 定义时初始化,字符串赋值 
//	char temp1[10]={"xin"};
	char temp1[10] = {'x', 'i', 'n'};
	p6 = temp1;
	p7 = &p6;
    printf("指针的指针: %c,%c,%c",temp1, *p6, **p7);
	printf("字符串数组:%s", temp1); 
	char temp2[10];
	// 单个元素字符赋值 
	temp2[0]='x';
	printf("字符数组: %s",temp2);
	
	system("pause");
	return 0;
}
  • Result
------指针的指针1------
指针的指针: x,x,x
------指针的指针2------
指针的指针: x,x,x字符串数组:xin字符数组: x
  • Analysis
    (1) 字符串数组定义时初始化可使用字符串如:char temp1[10]={“xin”};,使用时初始化,则需要单个字符赋值,如temp1[0]=‘x’;;
    (2) 指针的指针存储指针的地址,如*p6为一级指针,**p7为二极指针,存储一级指针的地址,如p7=&p6;;

3 链表

链表是一种数据结构,可动态进行存储分配.
在这里插入图片描述

图3.1 单向链表

特点:

根据需要实现增加,删除和插入节点.
链表有一个头指针head,仅存放地址,指向一个元素;
链表其他元素包括两个部分,即数据和指针,指针指向下一个节点的元素;
链表元素不是连续存储;
表尾地址为NULL,不指向任何元素,表示链表的结束;
链表的增删改查需要使用指针操作且链表的指向是连续的,中间不能断开;

3.1 静态链表操作

在这里插入图片描述

图3.2 链表结构
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

# define NULL 0

/* run this program using the console pauser or add your own getch, system("pause") or input loop */
/*建立结构体,添加指向结构体的指针,
  该结构体单元是链表的单个元素
*/
struct people{
	int age;
	char name[20];
	struct people *next;
};

typedef struct {
	int age;
	char name[20];
	struct Person *next;
}Person;

int main(int argc, char *argv[]) {
	struct people xin, tian, shui, *head, *p;
	/* 初始化链表元素*/
	xin.age = 10; strcpy(xin.name, "xindaqi");
	tian.age = 10; strcpy(tian.name, "lanlan");
	shui.age = 10; strcpy(shui.name, "qingqing");
	/*建立链表元素关系*/
	head = &xin;
	xin.next = &tian;
	tian.next = &shui;
	shui.next = NULL;
	p = head;
	printf("Age Name\n");
	do{
		printf("%d  %s\n",p->age, p->name);
		p = p->next;
	}while(p!=NULL);

	Person Jim, Green, *h, *p1;
	Jim.age = 22;
	strcpy(Jim.name, "Jim");
	Green.age = 23;
	strcpy(Green.name, "Green"); 
	h = &Jim;
	Jim.next = &Green;
	Green.next = NULL;
	p1 = h;
	printf("------typdef------\n");
	do {	
		printf("%d, %s\n", p1->age, p1->name);
		p1 = p1->next;
	}while(p1!=NULL);
	system("pause");
//	return 0;
}
  • Result
Age Name
10  xindaqi
10  lanlan
10  qingqing
------typdef------
22, Jim
23, Green
  • Analysis
    (1) 利用结构体建立链表元素单元,该结构体中含有指向结构体的指针变量;
    (2) 初始化链表,将结构体初始地址赋予指针头,依次利用next建立链表元素的连接;
    (3) 链接:p = head = &xin;将p指向结构体初始位置,而结构体中含有指针变量,当p指向该指针变量时,会自动指向该指针变量指向的下一个结构体初始位置,形成了链表结构;

4 总结

(1) 指针是变量的地址;指针变量名是地址;指针变量是存储地址的变量;
(2) 实参变量和形参变量通过单向值传递,进行数据交换,当函数调用结束后,形参变量即被释放,即形参值的改变不能改变实参的改变;
(3) 通过改变实参变量指向的变量内容,可实现实参数据的改变;
(4) 链表元素单元是利用结构体建立的,该结构体中含有指向结构体的指针变量;
(5) 二维数组是数组的数组,可将二维数组理解为一维数组的元素为一维数组,因此二维数组的行可视为一维数组即(a[4][3]中的行a[0]视为int a[4]);
(6) 二维数组元素遍历可通过首元素依次偏移获取如score[0]+n,其中n为二维数组元素,n小于二维数组元素总个数;
(7) 二维数组普通元素寻址有4种方式:

序号取地址描述
1&score[i][j]取地址符号&和索引下标取地址
2score[i]+j每行初始地址和列偏移量取地址
3score[0]+n数组第一个元素首地址和其他元素偏移量取地址
4*(score+i)+j每行地址和列偏移量取地址

(8) 二维数组每行首元素有6种寻址方式:

序号取地址描述
1&score[i][0]取地址符号&和索引下标取地址
2score[i]+j每行初始地址和列偏移量取地址
3score[0]+n数组第一个元素首地址和其他元素偏移量取地址
4*(score+i)每行地址和列偏移量取地址
5score+i第一个元素首地址和行偏移量获取地址
6score[i]按行取地址

[参考文献]
[1][谭浩强著.C程序设计(第二版).北京:清华大学出版社,1999]
[2]https://blog.csdn.net/qq_36561650/article/details/81069194
[3]https://blog.csdn.net/endeavor_g/article/details/80552680
[4]https://blog.csdn.net/qq_34707315/article/details/77318444
[5]http://c.biancheng.net/view/368.html


  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天然玩家

坚持才能做到极致

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值