C语言指针概述:访问内存的两种方式及指针的概念解析
[id_1248056978]id_9[id_1473728582[id_[id_2106610559]910[id_272389338]241]384723]

C语言能够获取变量地址。C语言具备操纵地址的能力。用来操作地址的特殊数据类型是指针。
简而言之 指针是一种数据类型 用于表示内存地址 所以借助指针变量 能够对内存灵活操作
1.访问内存的两种方式
直接访问:每个被定义的变量都具备两个属性。其一为变量值,其二是变量地址。变量地址展现出该变量于内存里存储的位置。变量值即为该内存当中的内容。所以要访问该空间上的内容,能够直接运用变量名
int a = 241;printf("%d",a);
[id_1938839228]
来获得变量的地址。再使用指针操作符来获得该地址的内容。
int a = 241;*(&a);
2.指针的概念
表示内存地址的数据类型是指针类型。所以地址是指针。一个变量的地址是指针型常量。用来保存地址的变量是指针型变量。
它存储在了地址为0016的地方
它有个指针叫b。因为地址就是指针。所以该指针的值是a的地址。也就是0016。指针的地址是1010。
所以这里b叫作指针变量。
指针变量的属性:
指针变量有其地址。该地址是为指针变量分配的内存空间的地址。
2、指针变量的值,指针内存空间上的内容。(0016)
也被称作指针指向的空间地址
4、指针指向的内存空间的内容。(241)
指针变量的值与它所指向空间的地址值相同。指针变量的值是内存空间的内容,能够改变。指针变量指向空间的地址是内存空间的地址,属于常量,不能被改变。
3.指针变量的定义
指针类型由两部分构成。一部分是数据类型名。另一部分是指针操作符。数据类型名声明了指针变量所指向的内存空间中存储的数据类型。
数据类型名 * 指针变量名
该指针变量cp指向一个char型内存空间int * ip;//指针变量ip指向一个int型内存空间该指针变量fp指向一个Int型内存空间
范例1
#includeint main(void){printf函数输出内容为"sizeof(int *) = "加上sizeof(int *)的结果值。 其中printf函数用于格式化输出。 "sizeof(int *)"表示获取int指针类型的大小。 整句话将该大小值以特定格式输出。将其大小以十进制整数形式输出 并与"sizeof(char *) = "拼接后打印显示输出"sizeof(float *) = "以及sizeof(float *)的结果值换行显示return 0;}
指针类型所占空间与其指向的内存存储的数据类型无关。
二、指针的使用1.指针变量的赋值
为指针变量赋值 是为指针设定其所指向内存空间的过程 给指针变量赋值 必须赋给它一个地址
char c = 'a';char * cp;cp = &c;//指针指向c的地址,用&取c的地址printf("%c",c);printf("%c",*cp);这句打印和上面一句效果一样。都是把c打印出来。
范例2
指针可以访问和修改变量
#includeint main(void){int a = 2;int *b;b = &a;printf("\ta = %d\n",a);//直接访问输出“\t*b = %d\n”,其中*d为间接访问时b所指向的值*b = 3;//改变指向空间的内容打印输出“After \"*b = 3\":\n”printf("\ta = %d\n",a);printf("\t*b = %d\n",*b);return 0;}
范例3
指针变量的值在一次赋值后,可以再次被赋值为其他地址。
在输出符时,对于指针的值、地址符的输出用%p
#includeint main(void){int a = 2;int b = 3;int *p;printf("&a = %p\n",&a);printf("&b = %p\n",&b);输出“After definition:”printf("\t&p = %p\n",&p);printf("\tp = %p\n",p);//printf("\t*p = %d\n",*p);p = &a;//将p赋值为a的地址内容为:After "p = &a":printf("\t&p = %p\n",&p);printf("\tp = %p\n",p);printf("\t*p = %d\n",*p);p = &b;//改变p的指向输出“After \"p = &b\":”之后换行printf("\t&p = %p\n",&p);printf("\tp = %p\n",p);printf("\t*p = %d\n",*p);return 0;}
的过程
2.将指针变量赋值为整数
原则上,整数数值不能被赋值给指针变量。不然的话,指针变量会指向内存空间。该内存空间的地址值就是那个整数数值。
但是如果该整数值空间是有效的,那么可以使用。
范例4
使用scanf函数将整数赋值给指针变量
#includeint main(void){int a = 1;int *p;printf("a = %d\n",a);printf("&a = %p\n", &a);这是在输出地址的时候使用%p打印输出“输入a的地址:”scanf("%p",&p);printf("*p = %d\n",*p);printf("p = %p\n",p);return 0;}
3.初始化指针变量
使用指针时最好对其进行初始化。不然指针会指向一个未知的空间。
int a = 0;int *p1 = &a;int *p2 = NULL;
NULL的值为0,它是指针型数值中约定的0值的表示形式。
4.const指针
指向const的指针变量
int const *p;const int *p;
声明一个指针变量p。它指向存储const int型数据的内存空间。这类指针所指向内存空间的内容不可变
const int a = 1;const int *p1 = &a;*p1 = 2; //*p1已经为1,不能为2
const型指针变量
int *const p;
const型指针变量所指向的内存空间具有固定性。一旦完成初始化,便无法使其指向别的空间。
int a = 1;int b = 2;int *const p = &a;*p = 12;//正确p 等于取 b 的地址。指针变量的值是不可改变的。也就是说不能改变其指向的内存空间地址。
指向const的const指针变量
const int *const p;
该指针变量的值和该指针指向的空间的值都是不可改变的。
int a = 1;int b = 2;int const *const p = &a;*p = 12;//错误p = &b;//错误
三、指针与函数
指针变量也可以作为函数参数使用。
指针形参
函数调用之际。会把实参的值赋予形参。运用指针变量当作函数参数。能够把一个内存空间的地址传至函数里。可凭借该地址去操作此地址上的内存空间。
void func(int *pt,int a);int *p;int x,y;x = 5;y = 20;p = &x;func(p,y);
这里把实参y传给形参a,a会被赋值为20。p是x的地址,把p赋给指针*pt,pt所指向的内容是5。
指针能够在函数内改变函数外的值。它是通过地址来传递值的。这种传递值的方式被称作地址传递。
范例5
使用指针作为形参的函数实现两个数的交换
#includevoid swap(int *pt1,int *pt2){//输入一个中间变脸int tmp;printf("pt1 = %p\n",pt1);printf("pt2 = %p\n",pt2);printf("*pt1 = %d\n",*pt1);printf("*pt2 = %d\n",*pt2);//用指针进行交换tmp = *pt1;*pt1 = *pt2;*pt2 = tmp;printf("*pt1 = %d\n",*pt1);printf("*pt2 = %d\n",*pt2);}int main(void){int a,b;int *p1 = NULL;int *p2 = NULL;打印输出“请输入两个数字: ”scanf("%d",&a);scanf("%d",&b);p1 = &a;p2 = &b;//交换前的信息printf("p1 = %p\n",p1);printf("p2 = %p\n",p2);printf("*p1 = %d\n",*p1);printf("*p2 = %d\n",*p2);swap(p1,p2);//交换后的信息printf("*p1 = %d\n",*p1);printf("*p2 = %d\n",*p2);return 0;}
通过上面的指针使用,我大致总结出了如下规律:
定义指针时通常用ptr。使用时把ptr=&变量,这等同于将变量的地址赋予指针变量ptr。而要获取地址所指向内容时,用ptr就能取出该变量的值。
指针形参的使用方法:
定义一个含有指针变量形参的函数;
在主调函数中为该变量分配空间,并将一个指针变量指向该空间;
以这个指针变量为实参调用定义好的函数;
在函数内改变该指针指向的值;
函数返回后,主调函数中的变量已经被改变。
2.指针型函数
函数的函数返回值能够是指针型数据也就是地址 返回该类型值时 执行机制和返回其他类型完全一样 声明方式通常是
数据类型 * 函数名(形参列表)
int * max(int a,int b,int c);一个指针变量的值
范例6
使用指针变量作为函数返回值
#include函数返回值类型为指向整型的指针int *p = NULL;如果a指向的值大于b指向的值,那么将p设为a。否则,将p设为b。p = a;elsep = b;if(*p < *c)//如果c指向的值较大,将p设为cp = c;return p;}int main(void){int a = 0;int b = 0;int c = 0;int *p = NULL;打印出“请输入三个整数: ”scanf("%d",&a);scanf("%d",&b);scanf("%d",&c);//由于函数的形参是指针型,所有传入变量的地址p = max(&a,&b,&c);输出"The max is %d.\n",其中%d的值为*p指向的值return 0;}
此段程序把a、b、c三个数的地址传到max函数里。借助指针找到它们对应内存地址的值。接着进行对比。返回时返回的是指针变量。p等同于最大值得地址。再通过*p取地址。从而得到这个最大值。
3.函数型指针
函数存于代码区 它们有地址 若将函数变量赋给其他变量 需用函数型指针 函数型指针即指向函数的指针
函数的值被保存成这个函数的地址
假设有下面一个函数:
int func(常量整型a,常量整型b);
这时函数名字是func,那么函数的地址就是func的地址,函数的值存于func的这个地址当中。
使用该函数类型来定义一个函数型指针,方式如下:
返回值为整型
这里*fp两侧的小括号不可省!下面为该函数型指针赋值:
fp = func;(*fp) (5,6);
因为fp被赋予了函数变量func的地址,func的值等同于其地址,所以*fp能够获取func函数的地址。
函数型指针变量赋值时,左值与右值的类型必须完全一致。
范例7
使用函数型指针来调用函数
#include函数返回值为整型return a + b;}int main(void){定义一个函数型指针。该指针名为fp。它指向一个函数。这个函数有两个参数。第一个参数是const int类型的a。第二个参数是const int类型的b。fp = add;//将其赋值为add换行。输出“3 + 4 = ”以及调用函数指针*fp并传入3和4后的结果,结果以十进制整数形式换行显示printf("%p\n",add);printf("%p\n",&add);printf("%p\n",fp);printf("%p\n",*fp);return 0;}
可以看出函数的地址即函数的值。
4.void型指针
void型指针即无类型指针。它能够指向存储任意数据类型的空间。其定义形式如下:
void * 变量名;
void * p1 = "Goodbye";int型指针p2被赋值为p1 它可以被赋予任意类型的地址值 它也能够用作赋值表达式的右值
不能对void型指针做加减运算。对指针端的加减是基于指针指向类型空间的字节长度进行的。void型指针变量的地址空间类型未知。所以不能进行加减。
**void型指针通常用作函数的形参。**声明如下:
void * 函数名(形参类型);
void *func(int a);int *p1 = NULL;int *p2 = NULL;····将func函数返回值转换为指向int类型的指针并赋值给p1,func函数的参数为int类型的大小func函数的参数为sizeof(int)的结果
练习1
//使用指针从标准输入获取三个整数,并求其中最大值#includeint main(void){int a,b,c;int *p1 = &a;int *p2 = &b;int *p3 = &c;scanf("%d %d %d",p1,p2,p3);if(*p1 < *p2){ //比较地址中的内容p1 = p2; //将p2地址赋给p1}if(*p1 < *p3){p1 = p3;}printf("Max is %d\n",*p1);return 0;}
练习2
//实现一个可以初始化各种类型数据的函数#include使空值初始化,将指针p作为参数传入,类型为字符型typeswitch(type){case 'i': //int型然后取该指针所指内容并赋值为0break;case 'c': //char型然后取该指针所指内容并赋值为'\0'break;case 'l': //long long型然后取出该指针指向的内容并除以2break;case 'f': //double型然后取该指针所指向内容并赋值为0.0break;case 'p': //指针类型将p强制类型转换为指向字符指针的指针。然后使该指针所指向的内容为空。break;default: //错误类型printf("Error type!\n");break;}}
四、指针与数组
指针能够用来指向数组。指针还能够用来指向数组中的一个元素。当指针指向数组时。可借助指针访问数组中的元素。
1.指向数组元素的指针
指向数组元素的指针是一种指针变量。它所指向的空间归属于数组中的某一个元素。例如:
int array[10] = {0};int *p0 = &array[0];/*等效于*/int *p0 = array;
这是因为数组的第0个元素的地址就是数组的地址。
2.指针访问数组
就能获得该元素的地址
范例8
#include#define SIZE 10int main(void){char a_ch[SIZE] = "Student";数组元素依次为1 2 3 4 5 6 7 8 9 10char *p_ch = a_ch;int *p_int = a_int;//使用索引法输出两个元素的地址输出“&a_ch[4] = %p, &a_ch[3] = %p\n”,参数为&a_ch[4]和&a_ch[3]//使用索引法输出两个元素之间的地址偏移量输出&a_ch[4]减去&a_ch[3]的结果//使用索引法输出两个元素的地址printf("&a_int[4] = %p, &a_int[3] = %p\n", &a_int[4], &a_int[3]); 可改写为:printf("&a_int[4] 的值为 %p,&a_int[3] 的值为 %p\n", &a_int[4], &a_int[3]); ,不过需注意这是基于代码内容的改写,原句本身是一段代码语句,改写后的内容同样是代码语句,只是表述略有不同。 严格按照要求去掉序号后,内容为:printf("&a_int[4] 的值为 %p,&a_int[3] 的值为 %p\n", &a_int[4], &a_int[3]); 。 但需说明的是,这样的改写对于代码语句来说意义不大,只是在符合规则下尽量调整了表述方式。//使用索引法输出两个元素之间的地址偏移量输出“&a_int[4] - &a_int[3] = ”以及&a_int[4]减去&a_int[3]的结果并换行//使用指针法输出两个元素的地址“p_ch + 3”的值为%p//使用指针法输出两个元素之间的地址偏移量其中%p处分别为p_int加4的值和p_int加3的值return 0;}
在计算两个地址的差的时候,为实际差/存储类型占字节大小
3.数组指针和数组变量
可以通过数组名和地址偏移量的组合来访问数组元素。
int array[5] = {1,2,3,4,5};printf("%d\n",*(array+2));
数组元素型指针与数组变量在很多方面是不同的:
值的可改变性不同
数组元素型指针的值能够改变。数组变量的值无法改变。
//可行int array_1[20] = {0};int array_2[20] = {0};int *p = array_1;p = array_2; //使指针指向另一个数组p++; //使指针指向数组array_2[1]//不可行array_1进行自增操作 //目的是让array_1的内容变为array1[1] 这是错误的array_1 = array_2; //错误
占用空间不同
数组变量占用的空间则由程序决定
访问方式不同
数组元素型指针访问方式为间接访问,而数组变量为直接访问。
范例9
#include#define SIZE 5int main(void){int a_int[SIZE] = {1,2};int *p_int = a_int;//输出数组元素型指针和数组变量的占用空间输出“sizeof(a_int) = %d\n”,其中%d为a_int的大小,这里a_int是数组变量输出“sizeof(p_int) = %d\n\n”,其中%d为p_int的大小。这里p_int是指针变量//输出数组第0个元素的值及其地址输出“a_int[0] = [%d]\n”,其中%d处为a_int[0]的值//这是第0个元素printf("&a_int[0] = [%p]\n\n", &a_int[0]); 这是第0个元素的地址//输出数组变量的三个属性printf("*a_int = [%d]\n",*a_int);这是a_int所指向的内容printf("a_int = [%p]\n", a_int); 这是用来输出a_int的值输出“&a_int = [%p]\n\n”,其中“%p”是“&a_int”的占位符,“&a_int”表示变量“a_int”的内存地址//输出数组元素型指针的三个属性printf("*p_int = [%d]\n",*p_int);这是p_int所指向的内容printf("p_int = [%p]\n", p_int); 这是输出p_int的值printf("&p_int = [%p]\n", &p_int);这是p_int的地址return 0;}
从上面例子能够得出:数组变量的值等于第2个元素的地址。第2个元素的地址又等于数组变量的地址。数组元素型指针的值等于第1个元素的地址。不过它的地址是另外一个地址。
4.数组指针作为函数形参
数组作为函数形参时,数组地址能用作函数调用的实参。声明形式存在以下几种情况:
//形式1数组大小为SIZE//形式2该函数接受一个整型数组作为参数//形式3该函数接受一个指向整数的指针作为参数
范例10
//验证上述3种方法都是指针变量#include#define SIZE 6数组大小为SIZE输出字符数组a的大小,格式为“char a[SIZE]: %d\n”,其中%d为a的大小数值}其长度为10000输出格式为"char a[10000]: %d\n" 其中%d为a大小值的占位符}void func_3(const char *a){输出字符指针a的大小,格式为“char *a: %d\n”}void func_4(const char a[]){最后以换行符结束输出}int main(void){字符数组a_char,大小为SIZE,其元素为'a'、'b'、'c'、'd'、'e'、'f'它被赋值为a_charprintf("sizeof(a):\n");func_1(a_char);func_2(p_char);func_3(a_char);func_4(p_char);return 0;}
一般情况下。为获得数组容量。通常把形式2改写为如下。通常把形式3改写为如下。
//形式2第二个参数是整型变量size//形式3第二个参数是整数类型,名为size
这种方式能够在函数刚开始的时候对数组容量作出判断。如此一来可以提升程序的安全性。
5.调用含数组形参的函数
它们的值都是数组的首地址
范例11
该函数能输出升序数组里大于或等于0的数组元素
#include#define SIZE 6另一个是常量整型n//n为要输出数组元素的个数int i = 0;for(i=0;iprintf("%4d",a[i]);}printf("\n");}int main(void){该序列是升序的int *p = a_int;while(*p < 0)++p; //将p后移输出从p开始的剩余数组元素。剩余数组元素的数量为SIZE减去(p与a_int的差值)。调用print_array函数,参数为p和SIZE减去(p与a_int的差值)return 0;}
数组的首地址是数组元素型指针变量
五、指针与二维数组二维数组的地址
对于二维数组,它在内存里是以转换为一维数组的形式进行存储的。首地址的表示形式为:
在使用时 可把一些含糊的变量或数值 赋给肯定不匹配的变量 以此诱发编译器 产生数据类型不匹配的警告信息 进而得知某变量的数据类型
int b = &a;
一般情况下,第m行第n列元素的地址有以下表示方法:
范例11
#include#define ROW_SIZE 3#define COL_SIZE 4int main(void){//初始化一个二维数组int array[ROW_SIZE][COL_SIZE] = {{1,2,3,4},{11,12,13,14},{21,22,23,24}};//输出各种变量的字节长度printf("sizeof(array) = %d\n", sizeof(array)); 这里数组大小为48 是因为12乘以4得到printf("sizeof(array[1]) = %d\n", sizeof(array[1])); 这里 4 乘以 4 等于 16printf("sizeof(array[1][0]) = %d\n",sizeof(array[1][0]));//1 x 4 = 4//输出数组首地址的各种形式的值printf("&array\t\t = %p\n", &array); 这行代码用于输出数组array的地址。它会在控制台显示出数组array的内存地址。具体来说,它使用printf函数,将格式化字符串"&array\t\t = %p\n"作为参数传入。其中,%p是格式说明符,表示以指针形式输出。&array则是获取数组array的地址。最终,程序会将数组array的地址按照指定的格式输出到控制台。输出“array” 输出制表符 输出等号 输出百分号“p” 输出换行符 输出数组的地址值printf函数输出:“&array[0] = ”,后跟&array[0]的地址值,以十六进制形式表示并换行。printf("&array[0][0]\t = %p\n",&array[0][0]);printf("*array\t\t = %p\n",*array);输出 "array[0]\t = %p\n",其中 %p 对应 array[0] 的值//输出数组中第1个一维数组首地址的各种表达形式的值printf("*(array+1)\t = %p\n",*(array+1));printf函数打印出&array[1]的地址值 格式为%p 并在前面加上“&array[1]\t = ”printf("&array[1][0]\t = %p\n",&array[1][0]);printf("*array+4\t = %p\n",*array+4);输出"array[1]\t = %p\n" 其中array[1]作为参数//比较*(array+1)和(*array+1)的不同printf("(array加上1)减去&array[0][0]等于%d\n(array+1) - &array[0][0]);printf("((array + 1) 减去 &array[0][0] 等于 %d\n", (*array+1) - &array[0][0]);return 0;}
2.指针法访问二维数组
使用指针法访问二维数组存在三种方式。其一为使用指向数组元素的指针。其二是使用一维数组型指针。其三是使用二维数组型指针
1.使用指向数组元素的指针
int a[3][2] = {{1,2},{11,12},{21,22}};int *p = *a; //即&a[0][0]这里是把数组第0个元素的地址赋予指针变量。并非把数组首地址赋予指针变量。由于3X2二维数组中第i行第j列元素可以表示为如下形式。*(*a + i * 2 +j)使用p代替*a,可得表达式如下:*(p + i * 2 + j)
2. 使用一维数组型指针
赋值为数组第0个一维数组的地址
int a[3][2] = {{1,2},{11,12},{21,22}};int (*p)[2] = a; //即&a[0]由于a中第m行第n列元素的地址可以表示为如下形式:*(*(a+m)+n)使用p来代替a,可得如下表达式:*(*(p+m)+n)
3. 使用二维数组型指针
int a[3][2] = {{1,2},{11,12},{21,22}};int (*p)[3][2] = &a;那么数组a中第m行第n列元素可以表示为:*(*表示第m个1维数组地址下的第n个偏量 这里是(*p+m)+n)的含义或*(**p+2*第m行n列元素相对第一个元素的偏移量为(2 * m + n),其中(2 * m + n)等于m与n之和的两倍。
3.二维数组形参
二维数组的地址能够用作函数的形参。传递二维数组地址时,有三种不同指针可作为形参来获取二维数组。
1. 数组元素型指针
把数组第一个元素的地址当作实参,赋值给形参。在函数里,利用该首地址与元素偏移量的组合,获取数组元素的地址。凭借地址来访问元素。
范例11
void print_array(int *p,const int row,const int col){int i,j;for(i=0;ifor(j=0;jprintf("%4d",*p++);printf("\n");}}void reverse(int *p,const int row,const int col){int i,j;for(j=0;jfor(i=0;iprintf("%4d",*(p+i*col+j));//首地址和元素偏移量组合printf("\n");}}int main(void){int array[ROW_SIZE][COL_SIZE] = {{1,2,3},{11,12,13},{21,22,23}};printf("Output the matrix:\n");print_array(*array,ROW_SIZE,COL_SIZE);//以*array为第一个实参调用函数printf("Reverse the matrix:\n");reverse(&array[0][0],ROW_SIZE,COL_SIZE);//以&array[0][0]为第一个实参调用函数return 0;}
2. 使用一维数组型指针
可以使用一维数组型指针作为形参来传递二维数组。
范例12
void print_array(int (*p)[COL_SIZE],const int row){/*数组型指针作为变量*/int i,j;for(i=0;ifor(j=0;jprintf("%4d",*(*p+j));//使用数组型指针访问数组元素printf("\n");++p;}}void reverse(int (*p)[COL_SIZE],const int row){int i,j;for(j=0;jfor(i=0;iprintf("%4d",*(*(p+i)+j));printf("\n");}}int main(void){int array[ROW_SIZE][COL_SIZE] = {{1,2,3},{11,12,13},{21,22,23}};printf("Output the matrix:\n");print_array(array,ROW_SIZE);//以array为实参调用函数printf("Reverse the matrix:\n");reverse(&array[0],ROW_SIZE);//以&array[0]为实参调用函数return 0;}
3. 使用二维数组型指针
范例13
void print_array(int (*p)[ROW_SIZE][COL_SIZE]){int i,j;for(i=0;ifor(j=0;jprintf("%4d",*(*(*p)+i*COL_SIZE+j));//方式1打印*(*(p + i)+j),宽度为4,按十进制整数形式输出printf("\n");}}int main(void){int array[ROW_SIZE][COL_SIZE] = {{1,2,3},{11,12,13},{21,22,23}};printf("Output the matrix:\n");print_array(&array);return 0;}
六、指针与字符1.字符指针
字符指针是指向字符型内存空间的指针变量,一般定义语句如下:
char *p = NULL;
访问字符数组:要实现对字符数组的访问。只需将字符指针赋值为字符数组的首地址。
char str[] = "Hello,world!";char *p = str;printf("%c",*(p+i)); //访问str中的某个元素printf("%s",p); //打印整个字符数组同时也可以使用p改变字符数组中的内容,例如:for(i=0;i<sizeof(str);i++)*(p+i) = '\0';
访问字符串:将字符串指针赋值为字符串常量的首地址。
char *p = "Hello World!";printf("%c",*(p+i)); //访问str中的某个元素printf("%s",p); //打印整个字符数组由于字符串常量是不可改变的,因此不能用p来改变字符串的内容
范例14
int main(void){char *p1 = "Hello, world!";char *p2 = "Hello, world!";char *p3 = "Hello, world"; //定义了一个与上面两个不同的字符串printf("%p\n",p1);printf("%d\n",sizeof(p1));printf("%p\n",p2);printf("%d\n",sizeof(p2));printf("%p\n","Hello, world!");printf("%d\n",sizeof("Hello, world!"));printf("%p\n",p3);printf("%d\n",sizeof(p3));return 0;}
2.字符指针使用示例
范例15
用字符指针达成字符串的比较功能。字符串之间大小比较的规则和strncmp函数一样。
int main(void){//初始化2个字符数组char str1[SIZE] = "\0";char str2[SIZE] = "\0";//定义两个字符指针指向这两个数组char *p1 = str1;char *p2 = str2;printf(请输入第一个字符串:);gets(p1);printf(请输入第二个字符串:);gets(p2);while(*p1 == *p2 && '\0' != *p1){++p1; //将p1后移++p2; //将p2后移}//根据p1和p2指向的值来判断比较结果if(*p1 == *p2)printf("They are same.\n");else if(*p1 > *p2)printf(第一个比第二个大。);elseprintf(第一个比第二个小。);return 0;}
范例16
使用字符指针将一个字符串的内容复制到另一个字符串中。
int main(void){char str1[SIZE] = "\0";char str2[SIZE] = "\0";char *p1 = str1;char *p2 = str2;printf(请输入源字符串:);gets(p1);//由于两个字符数组大小相同,因此不用考虑字符溢出while('\0' != *p1)*p2++ = *p1++;p2 = str2;printf(目标字符串是:);puts(p2);return 0;}
*p++和*(p++)的作用是一样的
在这里 *p2++ 和 *p1++ 的作用是,先对 p1 进行自增移位,接着用 * 取出其中的内容,以此实现一位一位地复制
3.字符指针数组
使用字符指针数组时,若不指定字符长度,会让每个字符串空间至少扩大为最长字符串所占空间,造成资源浪费。所以可使用字符指针数组,在数组里保存字符指针,每个指针指向特定字符常量。
范例17
使用啊字符指针数组对字符串进行排序
int main(void){char * p[NUM] = {NULL};int i,j;char * tmp = NULL;//数组内的有效字符指针个数必须等于NUMp[0] = "Nelson Aldrich";p[1] = "A. Piatt Andrew";p[2] = "Frank Vanderlip";p[3] = "Henry P.Davison";p[4] = "Charles D.Norton";//对数组中的字符串排序for(i=0;i-1 ;i++){for(j=i+1;jif(0<strcmp(p[i],p[j])){//互换两个指针指向的字符串tmp = p[i];p[i] = p[j];p[j] = tmp;}}}for(i=0;iputs(p[i]);return 0;}
而不是字符串数组
练习1
设计一个函数。该函数要实现strlen函数的功能。也就是要返回传入字符串的字符长度。
int my_strlen(char *p){int count = 0;while(*p != '\0'){ //如果*p为字符终止符,则结束循环++p; //后移*p++count; //有效字长加1}return count;}int main(void){char str[SIZE] = "\0";puts("Please input a string:");gets(str);//*p = str,是一种指针访问数组的方式printf(换行符为\n。,my_strlen(str));return 0;}
练习2
设计一个取子字符串的函数,函数声明包括以下信息:
源字符串、子字符串开始位置、子字符串字符个数
char *my_substr(char *src, //源字符串const int size_src, //源字符串空间大小char *dest, //目的字符串const int size_dest,//目的字符串空间大小const int start, //子字符串开始位置const int n) //子字符串字符个数{char *tmp = dest;int count = 0;//检测各类异常if(NULL == src || NULL若目标地址无效 或起始位置大于等于源数据大小 或数量大于目标数据大小printf(函数my_substr出现错误。换行符\n表示换行。错误信息为:"Error in function my_substr.\n");return NULL; //如果错误,返回}//实现子字符串的复制for(src += start,count = 0;count < n && *src != '\0';++count)*dest++ = *src++;return tmp;}int main(void){char p[SIZE] = "\0";char sub_str[SIZE] = "\0";int start = 0;int n = 0;puts("Please input a string:");gets(p);printf(请输入子字符串的起始位置:);scanf("%d",&start);printf(请输入子字符串的长度位置:);scanf("%d",&n);puts对p从起始位置start开始截取长度为SIZE的子串赋值给sub_str截取长度也为SIZE 执行my_substr函数操作return 0;}}
原文链接: