C语言指针概述:访问内存的两种方式及指针的概念解析

[id_1248056978]id_9[id_1473728582[id_[id_2106610559]910[id_272389338]241]384723]

C语言指针概述:访问内存的两种方式及指针的概念解析

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

#include 
int 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

指针可以访问和修改变量

#include 
int 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

#include 
int 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函数将整数赋值给指针变量

#include 
int 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

使用指针作为形参的函数实现两个数的交换

#include 
void 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; else p = b; if(*p < *c)//如果c指向的值较大,将p设为c p = 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

//使用指针从标准输入获取三个整数,并求其中最大值#include 
int 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作为参数传入,类型为字符型type switch(type){ case 'i': //int型然后取该指针所指内容并赋值为0 break; case 'c': //char型然后取该指针所指内容并赋值为'\0' break; case 'l': //long long型然后取出该指针指向的内容并除以2 break; case 'f': //double型然后取该指针所指向内容并赋值为0.0 break; 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 10
int main(void){ char a_ch[SIZE] = "Student";数组元素依次为1 2 3 4 5 6 7 8 9 10
char *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 5
int 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_char
printf("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;i printf("%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 4
int 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 等于 16 printf("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

#include 
#define ROW_SIZE 3#define COL_SIZE 3
void print_array(int *p,const int row,const int col){ int i,j; for(i=0;i for(j=0;j printf("%4d",*p++); printf("\n"); }}

void reverse(int *p,const int row,const int col){ int i,j; for(j=0;j for(i=0;i printf("%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

#include 
#define ROW_SIZE 3#define COL_SIZE 3
void print_array(int (*p)[COL_SIZE],const int row){ /*数组型指针作为变量*/ int i,j; for(i=0;i for(j=0;j printf("%4d",*(*p+j));//使用数组型指针访问数组元素 printf("\n"); ++p; }}

void reverse(int (*p)[COL_SIZE],const int row){ int i,j; for(j=0;j for(i=0;i printf("%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

#include 
#define ROW_SIZE 3#define COL_SIZE 3
void print_array(int (*p)[ROW_SIZE][COL_SIZE]){ int i,j;
for(i=0;i for(j=0;j printf("%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

#include 
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函数一样。

#include #define SIZE 256
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(第一个比第二个大。); else printf(第一个比第二个小。); return 0;}

范例16

使用字符指针将一个字符串的内容复制到另一个字符串中。

#include #define SIZE 256
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

使用啊字符指针数组对字符串进行排序

#include #include #define NUM 5
int main(void){ char * p[NUM] = {NULL}; int i,j; char * tmp = NULL;
//数组内的有效字符指针个数必须等于NUM p[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;j if(0<strcmp(p[i],p[j])){ //互换两个指针指向的字符串 tmp = p[i]; p[i] = p[j]; p[j] = tmp; } } }
for(i=0;i puts(p[i]);
return 0;}

而不是字符串数组

练习1

设计一个函数。该函数要实现strlen函数的功能。也就是要返回传入字符串的字符长度。

#include #define SIZE 256
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

设计一个取子字符串的函数,函数声明包括以下信息:

源字符串、子字符串开始位置、子字符串字符个数

#include #define SIZE 256
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;}}

原文链接:

你可能想看:
« 上一篇
下一篇 »

相关推荐

FreeBasic:强大免费开源的64位basic编译器及应用优势

2025年05月10日

81阅读

脊柱侧弯矫正方法大盘点:运动康复、支具矫正等多种方式

2025年05月09日

84阅读

如何在winForm标题栏去掉标题文字且任务栏图标正常显示

2025年05月09日

82阅读

十一黄金周促销广告词大全,国庆购物狂欢等你来

2025年05月09日

77阅读

关闭快速编辑模式及插入模式,设置控制台指定文字颜色举例

2025年05月09日

62阅读

黄金搭档低糖高钙饮品包装及成分功效全解析,适合人群要知晓

2025年05月09日

90阅读