指针是C语言中的一个重要的概念,也是C语言的一个重要特色。 数据在内存中的存储和读取如下: 在C语言中,对变量的访问有两种方式: 在C语言中,指针是一种特殊的变量,它是存放地址的。 *:是取值操作符; 如: 知道了一个变量的地址,就可以通过这个地址来访问这个变量,因此,又把变量的地址称为该变量的指针。 定义指针变量的一般形式为: 其中,*表示这是一个指针变量,变量名即为定义的指针变量名,类型说明符表示本指针变量所指向的变量的数据类型。 下面都是合法的定义: 可以用赋值语句使一个指针变量得到另一个变量的地址,从而使它指向一个该变量,如下: 将float型变量的地址放到指向整型变量的指针变量中,是错误的。 指针变量中只能存放地址(指针),不要将一个整数(或任何其他非地址类型的数据)赋给一个指针变量,否则编译器也会把该值当成一个地址来处理。 如 通过指针变量访问整型变量练习如下: 打印: 运行原理如下: 如果已执行了语句 (3) 练习: 打印: 执行原理如下: 指针变量作为函数参数练习: 打印: 执行过程如下: 练习: 打印: 一个变量有地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。 定义一个指向数组元素的指针变量的方法,与以前介绍的指向变量的指针变量相同。 把a[0]元素的地址赋给指针变量p,也就是使p指向a数组的第0个元素,如下图: 引用一个数组元素,有2种方式: 其中的a是数组名,p是指向数组元素的指针变量,其初值p=a。 练习: 方式一代码如下: 打印: 方式二代码如下: 运行效果与方式一相同。 方式三代码如下: 运行效果与之前相同。 形式为: 在编译时是将arr按指针变量处理的,相当于将函数f的首部写成 C语言调用函数时虚实结合的方法都是采用值传递方式,当用变量名作为函数参数时传递的是变量的值,当用数组名作为函数参数时,由于数组名代表的是数组首元素地址,因此传递的值是地址,所以要求形参为指针变量。 练习: 打印: 指针方式代码如下: 与第一种方式运行效果相同。 练习: 打印: 指针方式: 数组名作函数参数归纳: (2)实参用数组名,形参用指针变量,如: (3)实参形参都用指针变量。例如: (4)实参为指针变量,形参为数组名,如: 练习: 打印: 用指针变量可以指向一维数组中的元素,也可以指向多维数组中的元素; 可以认为二维数组是数组的数组,如定义 在二维数组中,常见表达式及其含义如下: 打印: 把二维数组a分解为一维数组a[0]、a[1]、a[2]之后,设p为指向二维数组的指针变量,可定义为: 它表示p是一个指针变量,它指向包含4个元素的一维数组。 其中类型说明符为所指数组的数据类型,*表示其后的变量是指针类型,长度表示二维数组分解为多个一维数组时,一维数组的长度,也就是二维数组的列数。 练习: 打印: 练习: 打印: 字符数组形式: 练习: 打印: 存放原理如下: 指针形式: 练习: 打印: 对字符串中字符的存取,可以用下标方法,也可以用指针方法。 练习: 打印: 指针方法: 执行效果与下标法相同。 练习: 打印: 形参用字符指针变量代码如下: 运行效果与之前相同。 代码还可以进行简化或改写: 简化2: 简化3: 简化4: 简化5: 简化6: 这个方式变得稍复杂了点,重在说明方法。 虽然用字符数组和字符指针变量都能实现字符串的存储和运算,但它们二者之间是有区别的,不应混为一谈。 而对字符指针变量,可以采用下面方法赋值: 但注意赋给a的不是字符,而是字符串第一个元素的地址。 而对数组的初始化 (4)如果定义了一个字符数组,在编译时为它分配内存单元,它有确定的地址;而定义一个字符指针变量时,给指针变量分配内存单元,在其中可以放一个字符变量的地址也就是说,该指针变量可以指向一个字符型数据,但如果未对它赋予一个地址值,则它并未具体指向一个确定的字符数据。 是可以的,下面的方式: 虽然一般也能运行,但这种方法是危险的。 改变指针变量的值测试: 打印: 若定义了一个指针变量,并使它指向一个字符串,就可以用下标形式引用指针变量所指的字符串中的字符。 下标形式引用指针变量测试: 打印: 可以用指针变量指向整型变量、字符串、数组,也可以指向一个函数。一个函数在编译时被分配给一个入口地址,这个函数的入口地址就称为函数的指针。 练习: 打印: 指针方式: 执行效果与常规方式相同。 函数指针变量常用的用途之一是把指针作为参数传递到其他函数。 其大致原理如下: 练习: 打印: 一个函数可以带回一个整型值、字符值、实型值等,也可以返回指针型的数据,即地址。 例如 练习: 打印: 改进: 打印: 这两个概念都是简称: 指针数组的概念: 例如 练习: 打印: 练习: {“baidu.com”, “www.baidu.com”, “pan.baidu.com”, “baidu.com/profile”} 实现思路: 代码如下: 打印: 定义一个指向指针数据的指针变量,形式下如: 例如 练习: 打印: 指针数组的一个重要应用是作为main函数的形参,在之前的程序中,main函数的第一行一般写成以下形式: 括号中是空的,实际上,main函数可以有参数,如 练习: 编译生成.exe可执行文件(这里文件名为pointer.exe),在命令行当前路径下执行: 打印: (1)指针变量加(减)一个整数 (2)指针变量赋值: (3)指针变量可以有空值,即该指针变量不指向任何变量,可以表示为 (4)两个指针变量可以相减: (5)两个指针变量比较 void真正发挥的作用在于: 例如 ANSI C新标准增加了一种void指针类型,即不指定它是指向哪一种类型数据的指针变量。 void指针可以指向任何类型数据,也就是说,可以用任何类型的指针直接给void指针赋值; const指针: 在定义 memcpy是memory copy的缩写,意为内存复制,在写C语言程序的时候,常常会用到它。 功能是从src的开始位置拷贝n个字节的数据到dest,如果dest存在数据,将会被覆盖。 练习: 打印:一、指针引入
正确而灵活地运用它,可以有效地表示复杂的数据结构;能动态分配内存;能方便地使用字符串;有效而方便地使用数组等。
掌握指针的应用,可以使程序简洁、紧凑、高效。可以说,不掌握指针就是没有掌握C的精华。1.地址的概念
内存区的每一个字节有一个编号,称为地址。
如果在程序中定义了一个变量,在对程序进行编译时,系统就会给这个变量分配内存单元。
如a=5;
。
系统在编译时,已经对变量分配了地址,例如,若变量a分配的地址是2000,则该语句的作用就是把常数5保存到地址为2000的单元。
如scanf("%d",&a);
。
调用函数时,把变量a的地址传递给函数scanf,函数首先把该地址保存到一个单元中,然后把从键盘接收的数据通过所存储的地址保存到a变量中。2.初识指针
假设我们定义了一个指针变量int *i_pointer
,通过语句i_pointer = &i;
来存放整型变量i的地址,如下:
将i的地址(2000)存放到i_pointer中,这时,i_pointer的值就是(2000) ,即变量i所占用单元的起始地址。
要存取变量i的值,可以采用间接方式:
先找到存放i的地址的变量i_pointer,从中取出i的地址(2000),然后取出i的值3,如下:
3.两个操作符
&:是取址操作符。int i = 2000; int *pointer; pointer = &i; printf("%dn", *pointer);
二、指针与指针变量
C语言中可以定义一类特殊的变量,这些变量专门用来存放变量的地址,称为指针变量。
指针变量的值(即指针变量中存放的值)是地址(即指针)。1.定义指针变量*
类型说明符 *变量名;
例如float *pointer_1;
中,指针变量名是pointer_1,而不是*pointer_1。float *pointer_3; // pointer_3是指向float型变量的指针变量 char *pointer_4; // pointer_4是指向字符型变量的指针变量
在定义指针变量时必须指定基类型。
需要特别注意,只有整型变量的地址才能放到指向整型变量的指针变量中,如下∶float a; int * pointer_1; pointer_1 = &a;
2.指针变量的引用&
C语言中提供了地址运算符&来表示变量的地址,其一般形式为:&变量名;
&a
表示变量a的地址,&b
表示变量b的地址。
当然,变量本身必须预先声明。#include <stdio.h> int main(){ int a, b; int *pointer_1, *pointer_2; a = 100; b = 10; pointer_1 = &a; pointer_2 = &b; printf("%d, %dn", a, b); printf("%d, %dn", *pointer_1, *pointer_2); return 0; }
100, 10 100, 10
3.对&和*运算符的说明
pointer_1 = &a;
:
(1)&*pointer_1
的含义是:
&和*两个运算符的优先级别相同,但按自右而左方向结合,因此先进行*pointer_1
的运算,它就是变量a,再执行&运算;
因此,&*pointer_1
与&a相同,即变量a的地址。
如果有pointer_2 = &*pointer_1;
,它的作用是将&*(a的地址)赋给pointer_2 ,如果pointer_2原来指向b,经过重新赋值后它已不再指向b了,而指向了a,如下:
(2) *&a的含义是:
先进行运算&a,得a的地址,再进行*运算,即&a所指向的变量,也就是变量a;
*&a和*pointer_1的作用是一样的,它们都等价于变量a,即*&a与a等价。(*pointer_1)++
相当于a++
。
其中,括号是必要的,如果没有括号,就成为了*pointer_1++
,而++和*为同一优先级别,而结合方向为自右而左,因此它相当于*(pointer_1++)
。
由于++在pointer_1的右侧,是后加,因此先对pointer_1的原值进行*运算,得到a的值,然后使pointer_1的值改变,这样pointer_1不再指向a了。
输入a和b两个整数,按先大后小的顺序输出a和b。
代码如下:#include <stdio.h> int main(){ int *p1, *p2, *p, a, b; scanf("%d %d", &a, &b); p1 = &a; p2 = &b; if(a < b){ p = p1; p1 = p2; p2 = p; } printf("a = %d, b = %dn", a, b); printf("max = %d, min = %dn", *p1, *p2); return 0; }
5 9 a = 5, b = 9 max = 9, min = 5
对输入的两个整数按大小顺序输出,需要用函数实现交换功能。
代码如下:#include <stdio.h> int main(){ void swap(int *p1, int *p2); int *pointer_1, *pointer_2, a, b; scanf("%d %d", &a, &b); pointer_1 = &a; pointer_2 = &b; if(a < b){ swap(pointer_1, pointer_2); } printf("%d > %dn", a, b); return 0; } void swap(int *p1, int *p2){ int temp; printf("Swaping......nPlease wait^_^n"); temp = *p1; *p1 = *p2; *p2 = temp; }
5 9 Swaping...... Please wait^_^ 9 > 5
输入a、b、c3个整数,按大小顺序输出。
代码如下:#include <stdio.h> int main(){ void exchange(int *p1, int *p2, int *p3); int *p1, *p2, *p3, a, b, c; scanf("%d %d %d", &a, &b, &c); p1 = &a; p2 = &b; p3 = &c; exchange(p1, p2, p3); printf("%d > %d > %dn", a, b, c); return 0; } void exchange(int *p1, int *p2, int *p3){ void swap(int *q1, int *q2); if(*p1 < *p2){ swap(p1, p2); } if(*p1 < *p3){ swap(p1, p3); } if(*p2 < *p3){ swap(p2, p3); } } void swap(int *q1, int *q2){ int temp; printf("Swaping......nPlease wait^_^n"); temp = *q1; *q1 = *q2; *q2 = temp; }
20 12 25 Swaping...... Please wait^_^ Swaping...... Please wait^_^ 25 > 20 > 12
三、数组与指针
指针变量既然可以指向变量,当然也可以指向数组元素(把某一元素的地址放到一个指针变量中)。
所谓数组元素的指针就是数组元素的地址。1.指向数组元素的指针
例如,int a[10];
定义a为包含10个整型数据的数组;
int *p
定义p为指向整型变量的指针变量。
应当注意,如果数组为int型,则指针变量的基类型亦应为int型。
对该指针变量赋值:p = &a[0];
2.通过指针引用数组元素
如a[i]
。
如*(a+i)
或*(p+i)
。
数组名即翻译成数组的第一个元素的地址。
输出数组中的全部元素:
假设有一个a数组,整型,有10个元素,要输出各元素的值有三种方法:
(1)下标法。
(2)通过数组名计算数组元素地址,找出元素的值。
(3)用指针变量指向数组元素。#include <stdio.h> int main(){ int a[10], i; for(i = 0; i < 10; i++){ scanf("%d", &a[i]); } printf("n"); for(i = 0; i < 10; i++){ printf("%d ", a[i]); } return 0; }
1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10
#include <stdio.h> int main(){ int a[10], i; for(i = 0; i < 10; i++){ scanf("%d", &a[i]); } printf("n"); for(i = 0; i < 10; i++){ printf("%d ", *(a + i)); } return 0; }
#include <stdio.h> int main(){ int a[10], i, *p; for(i = 0; i < 10; i++){ scanf("%d", &a[i]); } printf("n"); for(p = a; p < (a+10); p++){ printf("%d ", *p); } return 0; }
3.用数组名作函数参数
f(int arr[], int n)
f(int *arr, int n)
,这两种写法是等价的。
将数组a中n个整数按相反顺序存放,如下:
常规方式代码如下:#include <stdio.h> int main(){ void reverse(int x[], int n); int i, a[10] = {3, 7, 9, 11, 0, 6, 7, 5, 4, 2}; printf("The original array:n"); for(i = 0; i < 10; i++){ printf("%d ", a[i]); } printf("n"); reverse(a, 10); printf("The reversed array:n"); for(i = 0; i < 10; i++){ printf("%d ", a[i]); } printf("n"); return 0; } void reverse(int x[], int n){ int temp, i, j, m; m = (n - 1) / 2; for(i = 0; i <= m; i++){ j = n - i - 1; temp = x[i]; x[i] = x[j]; x[j] = temp; } }
The original array: 3 7 9 11 0 6 7 5 4 2 The reversed array: 2 4 5 7 6 0 11 9 7 3
#include <stdio.h> int main(){ void reverse(int *a, int n); int i, a[10] = {3, 7, 9, 11, 0, 6, 7, 5, 4, 2}; printf("The original array:n"); for(i = 0; i < 10; i++){ printf("%d ", a[i]); } printf("n"); reverse(a, 10); printf("The reversed array:n"); for(i = 0; i < 10; i++){ printf("%d ", a[i]); } printf("n"); return 0; } void reverse(int *x, int n){ int temp, *i, *j, *p, m; m = (n - 1) / 2; i = x; j = x + n - 1; p = x + m; for( ; i <= p; i++, j--){ temp = *i; *i = *j; *j = temp; } }
从10个数中找出其中最大值和最小值。
常规方式代码如下:#include <stdio.h> int max,min; int main(){ void find_max_min(int a[], int n); int i, a[10]; printf("Input 10 numbers:n"); for(i = 0; i < 10; i++){ scanf("%d", &a[i]); } find_max_min(a, 10); printf("max = %d, min = %dn", max, min); return 0; } void find_max_min(int a[], int n){ max = min = a[0]; int i; for(i = 1;i < n;i++){ if(a[i] > max){ max = a[i]; } else if(a[i] < min){ min = a[i]; } } }
Input 10 numbers: 3 7 9 11 0 6 7 5 4 2 max = 11, min = 0
#include <stdio.h> int max,min; int main(){ void find_max_min(int *a, int n); int i, a[10]; printf("Input 10 numbers:n"); for(i = 0; i < 10; i++){ scanf("%d", &a[i]); } find_max_min(a, 10); printf("max = %d, min = %dn", max, min); return 0; } void find_max_min(int *a, int n){ max = min = *a; int i; for(i = 1;i < n;i++){ if(*(a + i) > max){ max = *(a + i); } else if(*(a + i) < min){ min = *(a + i); } } }
如果有一个实参数组,想在函数中改变此数组中的元素的值,实参与形参的对应关系有以下4种情况:
(1)形参和实参都用数组名,如:void main(){ int a[10]; f(a, 10); } void f(int x[], int n){ ... }
void main(){ int a[10]; f(a, 10); } f(int *a, int n){ ... }
void main(){ int a[10], *p = a; f(a, 10); } void f(int *x, int n){ ... }
void main(){ int a[10], *p = a; f(p, 10); } void f(int x[], int n){ ... }
对数组中10个整数按由大到小顺序排序。
代码如下:#include <stdio.h> int main(){ void sort(int x[], int n); int i, *p, a[10] = {3, 7, 9, 11, 0, 6, 7, 5, 4, 2}; printf("The original array:n"); for(i = 0; i < 10; i++){ printf("%d ", a[i]); } p = a; sort(p, 10); printf("nThe sorted array:n"); for(i = 0; i < 10; i++){ printf("%4d", *p); p++; } return 0; } void sort(int x[], int n){ int i, j, k, t; for(i = 0;i < n - 1;i++){ k = i; for(j = i + 1;j < n;j++){ if(x[j] > x[k]){ t = x[j]; x[j] = x[k]; x[k] = t; } } } }
The original array: 3 7 9 11 0 6 7 5 4 2 The sorted array: 11 9 7 7 6 5 4 3 2 0
4.多维数组与指针
基本概念
但在概念上和使用上,多维数组的指针比一维数组的指针要复杂一些。int a[3][4] = {{1, 3, 5, 7}, {9, 11, 13, 15}, {17, 19, 21, 23}};
,二维数组a是由3个一维数组所组成的。
设二维数组的首行的首地址为2000,则有:
练习:
输出二维数组有关的值。
代码如下:#include <stdio.h> int main(){ int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; printf("a: %dn", a); printf("*a: %dn", *a); printf("a[0]: %dn", a[0]); printf("&a[0]: %dn", &a[0]); printf("&a[0][0]: %dn", &a[0][0]); printf("a+1: %dn", a+1); printf("*(a+1): %dn", *(a+1)); printf("a[1]: %dn", a[1]); printf("&a[1]: %dn", &a[1]); printf("&a[1][0]: %dn", &a[1][0]); printf("a+2: %dn", a+2); printf("*(a+2): %dn", *(a+2)); printf("a[2]: %dn", a[2]); printf("&a[2]: %dn", &a[2]); printf("&a[2][0]: %dn", &a[2][0]); printf("a[1]+1: %dn", a[1]+1); printf("*(a+1)+1: %dn", *(a+1)+1); printf("*(a[1]+1): %dn", *(a[1]+1)); printf("*(*(a+1)+1): %dn", *(*(a+1)+1)); return 0; }
a: 6487536 *a: 6487536 a[0]: 6487536 &a[0]: 6487536 &a[0][0]: 6487536 a+1: 6487552 *(a+1): 6487552 a[1]: 6487552 &a[1]: 6487552 &a[1][0]: 6487552 a+2: 6487568 *(a+2): 6487568 a[2]: 6487568 &a[2]: 6487568 &a[2][0]: 6487568 a[1]+1: 6487556 *(a+1)+1: 6487556 *(a[1]+1): 6 *(*(a+1)+1): 6
指向多维数组元素的指针变量
int (*p)[4]
若指向第一个一维数组a[0],其值等于a、a[0]、&a[0][0]等。
而p+i则指向一维数组a[i]。*(p+i)+j
是二维数组i行j列的元素的地址,而*(*(p+i)+j)
则是i行j列元素的值。
二维数组指针变量说明的一般形式为:类型说明符 (*指针变量名)[长度]
用指针变量输出二维数组元素的值。
代码如下:#include <stdio.h> int main(){ int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; int (*p)[4]; int i, j; p = a; for(i = 0;i < 3;i++){ for(j = 0;j < 4;j++){ printf("%4d", *(*(p + i) + j)); } printf("n"); } return 0; }
1 2 3 4 5 6 7 8 9 10 11 12
通过输入指定行数和列数打印出二维数组对应任一行任一列元素的值。
代码如下:#include <stdio.h> int main(){ int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; int (*p)[4], i, j; p = a; printf("i = "); scanf("%d", &i); while(i < 0 || i >= 3){ printf("i = "); scanf("%d", &i); } printf("j = "); scanf("%d", &j); while(j < 0 || j >= 4){ printf("j = "); scanf("%d", &j); } printf("a[%d, %d] = %dn", i, j, *(*p+i)+j); return 0; }
i = 3 i = 2 j = -1 j = 2 a[2, 2] = 5
四、字符串与指针
1.字符串定义
用字符数组存放一个字符串。
定义一个字符数组,对它初始化,然后输出该字符串。
代码如下:#include <stdio.h> int main(){ char string[] = "I love China!"; printf("%s", string); return 0; }
I love China!
用字符指针指向一个字符串。
定义一个字符指针,用字符指针指向字符串中的字符。
代码如下:#include <stdio.h> int main(){ char *string = "I love China!"; printf("%s", string); return 0; }
I love China!
2.字符串中字符的存取方法
将字符串a复制为字符串b。
下标法:#include <stdio.h> int main(){ char a[] = "I love China!",b[40]; int i; for(i = 0;*(a+i) != ' ';i++){ *(b+i) = *(a+i); } *(b+i) = ' '; printf("String a is: n%sn", a); printf("String b is: n"); for(i=0;b[i]!=' ';i++){ printf("%c", b[i]); } return 0; }
String a is: I love China! String b is: I love China!
#include <stdio.h> int main(){ char a[] = "I love China!",b[40], *p1, *p2; p1 = a; p2 = b; for( ;*p1 != ' ';p1++, p2++){ *p2 = *p1; } *p2 = ' '; printf("String a is: n%sn", a); printf("String b is: n"); int i; for(i=0;b[i]!=' ';i++){ printf("%c", b[i]); } return 0; }
3.字符指针作函数参数
用函数调用实现字符串的复制。
用字符数组做参数代码如下:#include <stdio.h> int main(){ void copy_string(char from[], char to[]); char a[] = "I am a teacher.", b[] = "You are a student."; printf("String a = %snString B = %sn", a, b); printf("Copy string a to string b:n"); copy_string(a, b); printf("String a = %snString B = %sn", a, b); return 0; } void copy_string(char from[], char to[]){ int i = 0; while(from[i] != ' '){ to[i] = from[i]; i++; } to[i] = ' '; }
String a = I am a teacher. String B = You are a student. Copy string a to string b: String a = I am a teacher. String B = I am a teacher.
#include <stdio.h> int main(){ void copy_string(char *from, char *to); char *a = "I am a teacher.", b[] = "You are a student."; printf("String a = %snString B = %sn", a, b); printf("Copy string a to string b:n"); copy_string(a, b); printf("String a = %snString B = %sn", a, b); return 0; } void copy_string(char *from, char *to){ for( ; *from != ' '; from++, to++){ *to = *from; } *to = ' '; }
注意:在定义和初始化b数组时不能通过指针方式,因为指针方式定义的数组为常量,存储在常量区,不可改变,因此调用函数改变b数组时会出现异常。
简化1:#include <stdio.h> int main(){ void copy_string(char *from, char *to); char *a = "I am a teacher.", b[] = "You are a student."; printf("String a = %snString B = %sn", a, b); printf("Copy string a to string b:n"); copy_string(a, b); printf("String a = %snString B = %sn", a, b); return 0; } void copy_string(char *from, char *to){ while((*to = *from) != ' '){ to++; from++; } }
#include <stdio.h> int main(){ void copy_string(char *from, char *to); char *a = "I am a teacher.", b[] = "You are a student."; printf("String a = %snString B = %sn", a, b); printf("Copy string a to string b:n"); copy_string(a, b); printf("String a = %snString B = %sn", a, b); return 0; } void copy_string(char *from, char *to){ while((*to++ = *from++) != ' '){ ; } }
#include <stdio.h> int main(){ void copy_string(char *from, char *to); char *a = "I am a teacher.", b[] = "You are a student."; printf("String a = %snString B = %sn", a, b); printf("Copy string a to string b:n"); copy_string(a, b); printf("String a = %snString B = %sn", a, b); return 0; } void copy_string(char *from, char *to){ while(*from != ' '){ *to++ = *from++; } *to = ' '; }
#include <stdio.h> int main(){ void copy_string(char *from, char *to); char *a = "I am a teacher.", b[] = "You are a student."; printf("String a = %snString B = %sn", a, b); printf("Copy string a to string b:n"); copy_string(a, b); printf("String a = %snString B = %sn", a, b); return 0; } void copy_string(char *from, char *to){ while(*to++ = *from++){ ; } }
#include <stdio.h> int main(){ void copy_string(char *from, char *to); char *a = "I am a teacher.", b[] = "You are a student."; printf("String a = %snString B = %sn", a, b); printf("Copy string a to string b:n"); copy_string(a, b); printf("String a = %snString B = %sn", a, b); return 0; } void copy_string(char *from, char *to){ for( ; *to++ = *from++; ){ ; } }
#include <stdio.h> int main(){ void copy_string(char *from, char *to); char *a = "I am a teacher.", b[] = "You are a student."; printf("String a = %snString B = %sn", a, b); printf("Copy string a to string b:n"); copy_string(a, b); printf("String a = %snString B = %sn", a, b); return 0; } void copy_string(char *from, char *to){ char *p1, *p2; p1 = from; p2 = to; while((*p2++ = *p1++) != ' '){ ; } }
4.字符指针变量和字符数组的比较
主要概括起来有以下几点:
(1)字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址(字符串第1个字符的地址),而不是将字符串放到字符指针变量中。
(2)赋值方式:
对字符数组只能对各个元素赋值,不能用以下办法对字符数组赋值。char str[20]; str = "I love China!";
char *a; a = "I love China!";
(3)初始化
对字符指针变量赋初值char *a = "I love China!";
等价于char *a; a = "I love China!";
char str[20] = {"I love China!"};
不能等价于char str[20]; str[] = "I love China!";
例如:char str[10]; scanf("%s", str);
char *a; scanf("%s", a);
(5)指针变量的值是可以改变的。#include <stdio.h> int main(){ char *a = "I am Corley!!"; printf("%sn", a); a += 7; printf("%sn", a); return 0; }
I am Corley!! rley!!
#include <stdio.h> int main(){ char *a = "I am Corley!!"; int i; printf("The sixth character is %cn", a[5]); for(i = 0; a[i] != ' '; i++){ printf("%c", a[i]); } printf("n"); return 0; }
The sixth character is C I am Corley!!
五、指向函数的指针
1.用函数指针变量调用函数
常规方式代码如下:#include <stdio.h> #if(1) int main(){ int max(int, int); int a, b, c; scanf("%d %d", &a, &b); c = max(a, b); printf("a = %d, b = %d, max = %dn", a, b, c); return 0; } #endif int max(int a, int b){ return a > b ? a : b; }
12 20 a = 12, b = 20, max = 20
#include <stdio.h> #if(1) int main(){ int max(int, int); int a, b, c; int (*p)(); p = max; scanf("%d %d", &a, &b); c = (*p)(a, b); printf("a = %d, b = %d, max = %dn", a, b, c); return 0; } #endif int max(int a, int b){ return a > b ? a : b; }
2.用指向函数的指针作函数参数
函数的参数可以是变量、指向变量的指针变量、数组名、指向数组的指针变量等;
指向函数的指针也可以作为参数,以实现函数地址的传递,这样就能够在被调用的函数中使用实参函数。//实参函数名 f1 f2 // ↓ ↓ void sub(int (*x1)(int), int (*x2)(int,int)){ int a, b, i, j; a = (*x1)(i); b = (*x2)(i, j); ... }
有一个函数(假设函数名为sub),它有两个形参(x1和x2),定义x1和x2为指向函数的指针变量。在调用函数sub时,实参为两个函数名f1和f2,给形参传递的是函数f1和f2的地址,这样在函数sub中就可以调用f1和f2函数了。
设一个函数process,在调用它的时候,每次实现不同的功能(有点类似多态)。
输入a和b两个数,第一次调用process时找出a和B中大者,第二次找出其中小者,第三次求a与b之和。
代码如下:#include <stdio.h> int main(){ int max(int, int); int min(int, int); int sum(int, int); void process(int, int, int(*fun)()); int a, b; printf("Input a and b:n"); scanf("%d %d", &a, &b); printf("Max = "); process(a, b, max); printf("Min = "); process(a, b, min); printf("Sum = "); process(a, b, sum); return 0; } int max(int a, int b){ return a > b ? a : b; } int min(int a, int b){ return a < b ? a : b; } int sum(int a, int b){ return a + b; } void process(int x, int y, int(*fun)()){ int result = (*fun)(x, y); printf("%dn", result); }
Input a and b: 12 20 Max = 20 Min = 12 Sum = 32
3.返回指针值的函数
这种带回指针值的函数一般定义形式为:类型名 *函数名(参数表列);
int *a(int x, int y);
。
有若干个学生的成绩(每个学生有4门课程),要求在用户输入学生序号以后,能输出该学生的全部成绩,用指针函数来实现。
代码如下:#include <stdio.h> int main(){ double scores[][4] = {{60.0, 70.0, 80.5, 90.5}, {56.0, 89.0, 67.0, 88.0}, {34.2, 78.5, 90.5, 66.0}}; double *search(double(*pointer)[4], int n); double *p; int i, m; printf("Please input the number of student:"); scanf("%d", &m); printf("The scores of No.%d are:n", m); p = search(scores, m); for(i = 0; i < 4; i++){ printf("%8.2f", *(p+i)); } return 0; } double *search(double(*pointer)[4], int n){ return *(pointer + n); }
Please input the number of student:2 The scores of No.2 are: 34.20 78.50 90.50 66.00
对于前面的练习,找出其中有不及格课程的学生及其学生号。
代码如下:#include <stdio.h> int main(){ double scores[][4] = {{60.0, 70.0, 80.5, 90.5}, {56.0, 89.0, 67.0, 88.0}, {34.2, 78.5, 90.5, 66.0}}; void *search(double(*pointer)[4], int n); double *p; int i, m; search(scores, 3); return 0; } void *search(double(*pointer)[4], int n){ int i, j; for(i = 0; i < n;i++){ double *p = *(pointer + i); for(j = 0; j < 4; j++){ if(*(p+j) < 60){ printf("No.%d has score below 60.n", i); break; } } } }
No.1 has score below 60. No.2 has score below 60.
指针函数和函数指针的区别
指针函数是指带指针的函数,即本质是一个函数;
函数指针是指向函数的指针变量,因而函数指针本身首先应是指针变量,只不过该指针变量指向函数。4.指针数组和指向指针的指针
一个数组,若其元素均为指针类型数据,称为指针数组,也就是说,指针数组中的每一个元素都相当于一个指针变量。
一维指针数组的定义形式为类型名 *数组名[数组长度];
int *name[4];
。#include <stdio.h> int main(){ int a[5] = {1, 2, 3, 4, 5}; int *p[5] = {&a[0], &a[1], &a[2], &a[3], &a[4]}; int i; for(i = 0; i < 5; i++){ printf("%5d", *p[i]); } printf("n"); return 0; }
1 2 3 4 5
将下边字符串按字母顺序(由小到大)输出:
声明一个数组指针来指向;
将排序利用strcmp()函数来解决;
各个功能抽象为函数或文件。#include <stdio.h> #include <string.h> int main(){ void sort(char *name[], int n); void print(char *name[], int n); char *name[] = {"baidu.com", "www.baidu.com", "pan.baidu.com", "baidu.com/profile"}; int n = 4; sort(name, n); print(name, n); return 0; } void sort(char *name[], int n){ char *temp; int i, j, k; for(i = 0; i < n - 1; i++){ k = i; for(j = i + 1; j < n; j++){ if(strcmp(name[k], name[j]) > 0){ k = j; } if(k != i){ temp = name[i]; name[i] = name[k]; name[k] = temp; } } } } void print(char *name[], int n){ int i; for(i = 0; i < n; i++){ printf("%sn", name[i]); } }
baidu.com baidu.com/profile pan.baidu.com www.baidu.com
类型名 **指针变量名;
char **p;
:
p的前面有两个*号,*运算符的结合性是从右到左,因此**p
相当于*(*p)
,显然*p
是指针变量的定义形式。
如果没有最前面的*,那就是定义了一个指向字符数据的指针变量;
现在它前面又有一个*号,表示指针变量p是指向一个字符指针变量的,*p就是p所指向的另一个指针变量。#include <stdio.h> #include <string.h> int main(){ char *name[] = {"baidu.com", "www.baidu.com", "pan.baidu.com", "baidu.com/profile"}; char **p; int i; for(i = 0; i < 4; i++){ p = name + i; printf("%sn", *p); } return 0; }
baidu.com www.baidu.com pan.baidu.com baidu.com/profile
5.指针数组作为main函数的形参
void main(){ ... }
void main(int argc, char *argv[])
,argc和argv就是main函数的形参。
main函数是由操作系统调用的,其形参的值不是在程序中得到,实际上实参是和命令一起给出的,也就是在命令行中包括命令名和需要传给main函数的参数。
命令行的一般形式为:命令名 参数1 参数2 …… 参数n
#include <stdio.h> #include <string.h> int main(int argc, char *argv[]){ int i; printf("The number of string is: %dn", argc - 1); for(i = 1;i < argc; i++){ printf("The string %d is: %sn", i, argv[i]); } return 0; }
pointer C Java Python
The number of string is: 3 The string 1 is: C The string 2 is: Java The string 3 is: Python
六、指针小结
1.数据类型小结
2.指针运算小结
例如p++、p–、p+i、p-i、p+=i、p-=i等。
将一个变量地址赋给一个指针变量,如: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;
。
如果两个指针变量都指向同一个数组中的元素,则两个指针变量值之差是两个指针之间的元素个数 ,如下:
图中p2-p1
的值为3。
若两个指针指向同一个数组的元素,则可以进行比较,指向前面的元素的指针变量小于指向后面元素的指针变量。3.void类型和const修饰指针
void abc(void);
。
例如,void *p;
表示指针变量p不指向一个确定的类型数据,它的作用仅仅是用来存放一个地址。
但是,如果需要将void指针的值赋给其他类型的指针,则需要进行强制类型转换。
当用const修饰指针时,根据const位置的不同有三种效果。
原则是:修饰谁,谁的内容就不可变,其他的都可变。const char *str = "Welcome to China!!n";
时,通过str = "Welcome to Beijing!!n";
改变字符串是合法的,而通过str[0] = 'w';
改变字符串是不合法的;
在定义char * const str = "Welcome to China!!n";
时,通过str[0] = 'w';
改变字符串是合法的,通过str = "Welcome to Beijing!!n";
改变字符串是不合法的;
在定义const char * const str = "Welcome to China!!n";
时,通过str[0] = 'w';
和str = "Welcome to Beijing!!n";
改变字符串是都是不合法的。扩展-memcpy
函数原型如下:void *memcpy(void *dest, const void *src, size_t n);
memcpy函数的返回值是dest的指针。
memcpy函数定义在string.h头文件里。#include <memory.h> #include <string.h> #include <stdio.h> char string1[60] = "The quick brown dog jumps over the lazy fox"; char string2[60] = "The quick brown fox jumps over the lazy dog"; void main() { printf( "Function:tmemcpy without overlapn" ); printf( "Source:tt%sn", string1 + 40 ); printf( "Destination:t%sn", string1 + 16 ); memcpy( string1 + 16, string1 + 40, 3 ); printf( "Result:tt%sn", string1 ); printf( "Length:tt%d charactersnn", strlen(string1)); memcpy( string1 + 16, string2 + 40, 3 ); printf( "Function:tmemmove with overlapn" ); printf( "Source:tt%sn", string2 + 4 ); printf( "Destination:t%sn", string2 + 10 ); memmove( string2 + 10, string2 + 4, 40 ); printf( "Result:tt%sn", string2 ); printf( "Length:tt%d charactersnn", strlen(string2)); printf( "Function:tmemcpy with overlapn" ); printf( "Source:tt%sn", string1 + 4 ); printf( "Destination:t%sn", string1 + 10 ); memcpy( string1 + 10, string1 + 4, 40 ); printf( "Result:tt%sn", string1 ); printf( "Length:tt%d charactersnn", strlen(string1)); }
Function: memcpy without overlap Source: fox Destination: dog jumps over the lazy fox Result: The quick brown fox jumps over the lazy fox Length: 43 characters Function: memmove with overlap Source: quick brown fox jumps over the lazy dog Destination: brown fox jumps over the lazy dog Result: The quick quick brown fox jumps over the lazy dog Length: 49 characters Function: memcpy with overlap Source: quick brown dog jumps over the lazy fox Destination: brown dog jumps over the lazy fox Result: The quick quick brown dog jumps over the lazy fox Length: 49 characters
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算