c语言指针运算作用,C语言指针讲解(三)

谨记

哎,我......觉得你变了,我怎么变了?你以前是那么的听话,那么的在乎我,总是想象美好的生活而奋斗,遇到困难不断的去尝试克服,生活的态度总是那样积极向上的。而如今的你,变得总是感慨这也不好,那也不好,总是觉得这也不适合你,那也不适合你,不知道自己要什么,自己的理想信念就不复存在了。你错了,其实我......并没有改变,而改变的是这个社会,我只是让社会虐待得体无完肤。那......你还能回到从前的你吗?我想......我回不到从前的我了,不过我想变得比从前的我更优秀,等着......我,好吗?,好,我等着你,然后我们一起前行......。相信大家读完这段话后,就觉得这大概应该是一队情侣之间的对话,其实不是,这是未来的你和现在的你的对话。人生亦是如此。

前言

本篇文章将讲解C语言指针的最后一点内容,const和指针,以及字符指针等相关内容,对于指针,常用的都已经介绍了,将来我们学了函数过后,对指针我们又的有一个重新的认识,后面也会将讲解指针和函数之间的关系。

const和指针

我们都知道,在我们以前申明一个变量,并且为其赋值,当我们需要改变变量的值的时候,就在给它赋值一次就行,比如: int a = 0; 这是申明一个变量a并为其赋值为0,然后如果程序需要,那么我们可以a = 20;这样就能改变变量的值为20.

不过在某一天某一个特定的场景,我们需要一个值永远也不要改变,在这个变量申明的时候给他一个初始值,之后他的值就不能改变了,那么这个时候我们就需要用一个C语言中的一个关键字const。

在C语言中,关键字const修饰变量,可以使得变量常量化。const修饰基本简单类型(非指针)时,很容易理解,就是变量的值不允许修改,比如下面的表达式:

int const m = 20;

const int m = 30;

上面这两种写法,变量m的值都不会被修改。

如果用const修饰指针变量,会使得指针变量常量化,但要注意const的位置。这里一般就3种情况:

常量化指针目标表达式

常量化指针变量

常量化指针变量及其目标表达式

常量化指针目标表达式

常量化指针目标是限制通过指针改变其目标的数值。一般说明形式如下:

const *=[ ]

我们可以通过一个示例代码来看

int main(int argc, char *argv[])

{

int m = 100, n = 200;

const int *p;

p = &m;

printf("1) %d %p %d %p\n", m, &m, *p, p);

m++;

printf("2) %d %p %d %p\n", m, &m, *p, p);

p = &n;

printf("3) %d %p %d %p\n", n, &n, *p, p);

#ifdef _DEBUG_

*p = n;

printf("4) %d %p %d %p\n", m, &m, *p, p);

#endif

return 0;

}

输出结果:

1) 100 0x7fff5fbff83c 100 0x7fff5fbff83c

2) 101 0x7fff5fbff83c 101 0x7fff5fbff83c

3) 200 0x7fff5fbff838 200 0x7fff5fbff838

Program ended with exit code: 0

这种情况下,编译程序时,没有调试debug任何选项时,相当于没有定义宏_DEBUG_,程序可以正常执行。可以看出,const int *p这种写法,允许修改p,指针p可以改变指向。

总之:“const int *p”,const的作用,限制了通过指针去修改指针的目标。但还可以直接修改m。

常量化指针变量

常量化指针变量,使得指针变量存储的地址值不能修改。一般说明形式如下:

*const = ;

int main(int argc, char *argv[])

{

int m = 100, n = 200;

int * const p = &m;

printf("1) %d %p %d %p\n", m, &m, *p, p);

m++;

printf("2) %d %p %d %p\n", m, &m, *p, p);

*p = n;

printf("3) %d %p %d %p\n", m, &m, *p, p);

#ifdef _DEBUG_

p = &n;

printf("4) %d %p %d %p\n", n, &n, *p, p);

#endif

return 0;

}

输出结果:

1) 100 0x7fff5fbff83c 100 0x7fff5fbff83c

2) 101 0x7fff5fbff83c 101 0x7fff5fbff83c

3) 200 0x7fff5fbff83c 200 0x7fff5fbff83c

Program ended with exit code: 0

这种情况下,编译程序时,即没有定义宏_DEBUG_,程序可以正常执行。因此,int *const p这种写法, *p可以被重新赋值,即允许通过指针p改变指针的目标值。

总之,“int * const p”,const的作用,使得指针变量的指向不能修改。但可以通过 * 指针变量名称去修改指针所指向变量的数值。

常量化指针变量及其目标表达式

一般说明形式如下:

const * const = ;

常量化指针变量及其目标表达式,使得既不可以修改的地址,也不可以通过*修改指针所指向变量的值。

void指针

void型的指针变量是一种不确定数据类型的指针变量,它可以通过强制类型转换让该变量指向任何数据类型的变量或数组。

一般形式为

void * ;

对于void型的指针变量,实际使用时,一般需通过强制类型转换才能使void型指针变量得到具体变量或数组地址。在没有强制类型转换之前,void型指针变量不能进行任何指针的算术运算。

int main(int argc, const char * argv[]) {

int m = 100;

void *p;

p = (void *)&m;

printf("%d %p %d %p\n", m, &m, *p, p);

return 0;

}

输出结果:这个程序诶报错,main.c:18:36: Argument type 'void' is incomplete,如果把上面的打印语句替换成这样 printf("%d %p %d %p\n", m, &m, *(int *)p, p);这样输出结果为:

100 0x7fff5fbff83c 100 0x7fff5fbff83c

Program ended with exit code: 0

在该程序中,使用void指针时,应该首先进行类型转换。尤其是引用指针的目标值,若没有经过转换,void *相当于类型不确定,只知道指针目标的起始地址,不知道其占用的字节数,没办法处理,是编译错误。类似的道理,如果void指针没有转换成具体的指针类型,也不可以进行指针的运算,因为,没办法决定以什么为单位来偏移。

对于void型的指针变量,实际使用时,一般需通过强制类型转换才能使void型指针变量进行指针的运算或得到其目标的值。

字符指针

字符指针就是存储字符变量的地址。在这里,重点介绍字符指针,是为了讲解字符指针在处理字符串及字符指针数组时的用法。

例子:输入一个字符串,倒序输出。

#include

#include

int main(int argc, char *argv[])

{

char s[10];

char *p, *q, t;

printf("input a string:");

scanf("%s", s);

p = s;

q = s + strlen(s) - 1;

while (p < q)

{

t = *p;

*p = *q;

*q = t;

p++;

q--;

}

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

return 0;

}

输出结果:

input a string:abc

cba

Program ended with exit code: 0

在该程序中,使用字符串为字符数组赋值。指针p指向字符串的第一个字符,指针q指向字符串的最后一个字符(结束符\0之前的字符),通过p++,q --来让指针分别指向待交换的两个字符。

初始化字符指针时,可以把内存中字符串的首地址赋予指针。这时,并不是把该字符串复制到指针中,而是让指针指向字符串的起始字符。

#include

int main(int argc, char *argv[])

{

char *s = "Welcome!";

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

s++;

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

#ifdef _DEBUG_

(*s)++;

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

#endif

return 0;

}

输出结果:

Welcome! Welcome!

Program ended with exit code: 0

这就是指向字符串的指针。请读者一定要注意,第一种方式是把字符串的内容保存在数组里,即数组的每一个元素保存一个字符。但指针变量只有4个字节,只能用来保存地址。因此,指针变量里的值是字符串“Welcome!”的首地址,而字符串本身存储在内存的其他地方。

注意

在使用字符指针指向字符数组时,有以下两点需要注意。

① 虽然数组名也表示数组的首地址,但由于数组名为指针常量,其值是不能改变的(不能进行自加、自减、赋值等操作)。如果把字符数组的首地址赋给一个字符指针变量,就可以移动这个指针来访问或修改数组中的字符。

② 在使用scanf时,其参数前要加上取地址符 &,表明是一个地址。如果指针变量的值已经是一个字符数组的首地址,那么可以直接把指针变量作为参数而不需要再加上取地址符&。

当程序中增加了语句“(*s)++”后,发现产生了段错误。在这里,读者要特别注意,当一个字符指针初始化为指向一个字符串常量时,不能对字符指针变量的目标赋值。从这个角度看,“char *s = "Welcome!"”相当于 “const char *s = "Welcome!"”,只是省略了const。

温馨提示:当一个字符指针初始化为指向一个字符串常量时,不能对字符指针变量的目标赋值。

字符指针数组

若数组中存储了若干个字符串的地址,则这样的数组就叫做字符指针数组。

示例代码:

#include

#include

int main(int argc, char *argv[])

{

char s1[] = "Welcome";

char s2[] = "to";

char s3[] = "farsight";

char* a1[3] = {s1, s2, s3};

char *a2[3] = {"Welcome", "to", "farsight"};

char **p;

int i;

p = a1;

printf("array1:%s %s %s\n", a1[0], a1[1], a1[2]);

for (i = 0; i < sizeof(a1) / sizeof(char *); i++)

printf("%s ", *(p+i));

printf("\n");

p = a2;

printf("array2:%s %s %s\n", a2[0], a2[1], a2[2]);

for (i = 0; i < sizeof(a1) / sizeof(char *); i++)

printf("%s ", *(p+i));

printf("\n");

return 0;

}

输出结果:

array1:Welcome to farsight

Welcome to farsight

array2:Welcome to farsight

Welcome to farsight

Program ended with exit code: 0

在该程序中,数组a1就是字符指针数组,分别存储了字符数组s1,s2,s3的起始地址。即数组a1含有3个指针,分别指向s1,s2,s3存储的3个字符串。类似的数组a2,也是字符指针数组,含有3个字符指针,分别指向了常量串“Welcome”,“to”,“farsight”。

需要注意的是字符指针数组的数组名,即代表数组的起始地址,或者第一个元素的地址。数组的元素已经是字符指针类型了,所以很容易理解,元素的地址就是二级指针。因此该程序中,使用二级指针p来对字符指针数组进行了遍历。

总结

到这篇文章结束为止,我们已经把C语言的重点学了一半了,那么C语言的指针就已经学完了,我希望读者能够认真的学习,希望把指针搞明白。

结尾

希望读者真诚的对待每一件事情,每天都能学到新的知识点,要记住,认识短暂,开心也是过一天,不开心也是一天,无所事事也是一天,小小收获也是一天,所以,你的路你自己选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值