注意:要在声明的时候进行初始化
声明的方式:类型名 * const 变量名
1.不能再指向别的变量,指针的value不可更改
[cpp]
#include<stdio.h> 
void main(){ 
    int a = 89; 
    int * const p = NULL; 
    p = &a; 
 

0.数组和指针并不是相同的

*/

*/ 出自: 快乐编程
*/ 作者: neverTheSame E-mail:zhaoxufeng9997@126.com QQ:475818502
*/ 时间: 2008-6-1
*/ 声明: 尊重作者劳动,转载请保留本段文字

 
报错:
error C2166: l-value specifies const object
2.可以通过指针为那个变量赋值(变量值不是const)
[cpp]
#include<stdio.h> 
void main(){ 
    int a = 89; 
    int * const cp = &a; 
    *cp = 188; 
    printf(“a=%dn”,a); 

我们声明数组时,同时分配了一些内存空间,用于容纳数组元素,但是当我们声明一个指针时,只分配了用于容纳指针本身的内存空间。

*/

对const使用的理解.

const对很多人来说既陌生又熟悉.可以说很棘手的问题,
有些地方很难理解.我在刚学C的时侯,对它的理解也是很模糊的.
好像有点理解,但又说不出个所以然来.
在此,就向大家分享,我一直以来对它的理解,如有不当之处请指教.

   const可以说一种常量的声明的关键字,如const int
a=2;变量a就是一个常变量,
a的值不能被改变,这个改变是一定意义上的不能改变.而是说值的改变不能直接通过a这个符号
来改变.但事实上,a的值是可能改变的.如下例子:
#include<stdio.h>
int main()
{
 const int a=3;
 int *p=(int*)&a;
 *p=100;
 printf(“%d”,a);
 return 0;
}
这样a的值就被改变了.
   const也可以说一种只读的关键字,如int integerArray[10]={0};const
int* pointer=integerArray;
这里pointer是指向一个常变量的指针变量.pointer指向可能改变,但它所指向的变量的值就不能直接通过pointer来改变.
如:*(p+1)=2;这是不可以的.但如果有另外一个数组integerArray1,p=integerArray1是可以有.
还有指向的变量不可改变,这种不可改变是一定意义的改变.
如下例子:
#include<stdio.h>
int main()

 int array[10]={0};
 const int *pointer=array;
 int *pointer1=(int*)pointer;
 pointer1[0]=1;
 printf(“%d”,array[0]);
 return 0;
}
以上例子说明了,不能直接通过pointer改变array,但可能间接通过pointer来改变array;
    现在说一说有const声明常指针,它的声明不像声明指向常量的指针形式.
它的声明形式为:int* const pointer;
.常指针在编程的过程中它的指向不能改变.
因此,常指针在声明的时侯一定要给它赋初值.否则,就不能直接给它赋值.
但是,如果一定要给它赋上一定的值,是可以的.如下例子:
#include<stdio.h>
int main()
{
 int a=2;
 int* const p;
 int **p1=(int**)&p;
 *p1=&a;
 printf(“%d”,*p);
 return 0;
}
   
经过上面的介绍,相信大家对指向常量的常指针的声明也不难写出吧.它的声明形式:
cont int* const
p;它就不用作过多的介绍了,指向常量的常指针就是指向常量的指针与
常指针的复合了.
    好了就说到这里吧.

 
结果:
a=188
Press any key to continue
3.const指针指向的是const变量,改变变量的值(在LINIX下可以实现)
[cpp]
#include<stdio.h> 
void main(){ 
    const int b = 89; 
    int * const pp = &b; 
    *pp = 100; 
    printf(“b = %dn”,b); 

从这个方面也可以理解sizeof后面跟数组名和指针名的不同。

第二种声明方式:const 类型名 * 变量名
1.pointer to constants 指向常量的指针
 
指向常量的指针,防止通过指针去修改变量的值,不管该变量是否是const变量
[cpp]
#include<stdio.h> 
void main(){ 
    int x = 123; 
    const int *pc = &x; 
    *pc = 8989; 
    printf(“%dn”,x); 

什么时候数组和指针相同呢?
c语言标准对此做了如下说明
规则1.表达式中的数组名被编译器当作一个指向该数组的一个元素的指针
规则2.下标总是与指针和偏移量相同

 
结果:不能修改
rror C2166: l-value specifies const object
2.指向常量的指针,该指针可以指向别的变量,指针的value是可以更改
[cpp]
void main(){ 
    int x = 123; 
    int y = 321; 
    const int *pc = &x; 
澳门新葡萄京官网首页 ,    printf(“%pn”,pc); 
    pc = &y; 
    printf(“%pn”,pc); 

规则3.在函数参数的声明中(形式参数),数组名被编译器当作指向该数组第一个元素的指针

 
3.指向常量的指针,不能赋值为一个普通的指针,因为指向常量的指针是不可以修改变量的值的,如果把它赋给了一个普通的指针,那么就可能www.2cto.com
实现修改变量的值,所以是不可以的
[cpp]
#include<stdio.h> 
void main(){ 
    int x = 123; 
    const int *pc = &x; 
    int *q = pc; 

1.数组名是一个常量指针,并不是一个左值

 
报错:
error C2440: ‘initializing’ : cannot convert from’const int *’ to ‘int
*’Conversion loses qualifiers
 
第三种声明方式:const int * const 变量名
该指针变量的值和该指针指向的空间的值都是不可改变的
 
 
 
加深:
[cpp]
#include<stdio.h> 
void main(){ 
//第一基本类型的const变量,const位置在哪儿都可以 
    const int x = 123; 
    const int y = 321; 
//定义一个非constbianl 
    int z = 111; 
//定义一个指向常量的指针 
    const int *p = &x; 
//定义一个常指针 
    int *const q = &z; 
//定义一个非const指针 
    int * w = &z; 
 
    x=y;//是错误的,因为const变量是不能修改的,而且const变量不能做左值 
   
p=&z;//正确,指向常量的指针的value的值是可以修改的,就是说可以指向别的变量,但是不能通过该指针去修改它所指向的内存空间 
 
的值 
    *p=10;//错误,指向常量的指针中,是不能通过指针来修改变量的值的 
    *p=y;//错误,同上 
    p=w;//正确,指向常量的指针他的value是可以修改的 
    z=5;//正确,z是一个变量,可以改变它的值 
    z=x;//正确,x作为const变量只能作为右值,不能作为左值 
    *q=x;//正确,const指针变量是可以修改它所指向的地址里面的值 
   
q=&x;//错误,因为x在这里是作为常量的存在,是不能改变的,而q这个指针是可以通过它来改变变量的值的 
         //不过原则是是可以的,标准c中是可以改变变量的值的 
   
w=&x;//错误,因为x在这里是作为常量的存在,是不能改变的,而w这个普通的指针是可以通过它来改变变量的值的 
         //不过原则是是可以的,标准c中是可以改变变量的值的 
   
w=p;//错误,因为指向常量的指针是不能改变它所指向的内存空间里的值的,而w这个普通的指针是可以通过它来改变变量的值的,所以 
 
不能把指向常量的指针赋给普通的指针 
   
w=q;//正确,因为q这个指针是可以通过它来改变变量的值的,而w这个普通的指针也是可以的 
 
     
}   

#include<stdio.h>

摘自 like7xiaoben 

int main(int argc,char **argv)

声明的方式:类型名
* const 变量名 1.不能再指向别的变量,指针的value不可更改 [cpp]
#includestdio.h void ma…

{
     int array[]={1,2,3,4};
     array++;
     return 0;
}

test.c|5| error: lvalue required as increment operand

数组名不是常量指针的情况只有两种,就是当数组名是sizeof和&的操作数时,前者产生整个数组的占用的字节数,后者产生一个指向数组的指针

2.下标引用和间接操作是一样的

 #include<stdio.h>
 int main(int argc,char **argv)
 {
     int array[]={1,2,3,4};
     int *b=array+1;
     printf(“%dn”,b[1]);
     printf(“%dn”,*(b+1));
     printf(“%dn”,b[-1]);
     printf(“%dn”,b[10]);
     printf(“%dn”,1[b]);
     return 0;
 }

输出
3
3
1
32595
3
这个例子说明了几个很有意思的事实,b是指针,但是b还是可以使用下标操作符,c在处理下标操作符时把b[1]看成*(b+1)
这也是为什么1[b]是合法的原因,1[b]被看成了*(1+b),在编译器看来b[1]和1[b]并没有区别

并且c语言不进行下标检查,这是基于相信coder的设计思想,并且检查下标要消耗一定的资源

3.当要传递一个数组是形参可以是两种形式
int strlen(char *string);
int strlen(char string[]);
//甚至是下面的方法都可以
int strlen(char string[100]);//里面的数字随意

void print1(int *a)
{
int i;
for(i=0;i < SIZE;i++)
printf(“%dn”,a[i]);
}
void print2(int a[])
{
int i;
for(i=0;i< 5;i++)
printf(“%dn”,a[i]);
}
//数组的下标使用变量是可以的
调用时,实参只能是一个指针
int a[]={1,2,3,4,5};
print1(a);
print2(a);
print2(&a[1]);//这样传过来就是数组的一部分。
实参即使不是真的数组都是合法的
int b=10;
print2(&b);
实际上传递的就是指针

这个相等行暗示指针和数组名是相等的,但千万不要被它糊弄了,这个声明确实相等,但是只存在于当前的这个上下文环境中。
sizeof 的不同
char *a = “hello”;
char b[]= {‘h’,’e’,’l’,’l’,’o’};
 //sizeof(a)是指针占的内存地址大小,所有类型的指针的大小都一样,是系统的字长,32位系统就是4个字节,64位系统就是8个字节
 //sizeof(b)是数组b占的字节数,这里是5个char加上一个‘’,是6个字节

注意指针在这里的用法,只能对字符串常量采用char *a = “hello”;
int *a = {1,2,3};             //error: (twice)excess element in scalar
initializer, initialization makes pointer from interger without a cast
char *b = {‘h’,’e’,’l’,’l’,’o’};//error:(four times)excess element in
scalar initializer, initialization makes pointer from interger without a
cast
char *c = ‘h’;            //error: initialization makes pointer form
interger without a cast
char *d = “h”; //correct

char *e =”hello” //correct

4.由第三条引出了第四条
先讲一下历史
由于 char
message[]={‘h’,’e’,’l’,’l’,’o’};这种初始化字符数组的方式用于比较长的字符数组显得比较傻,c语言标准提出了一种快速方法用于初始化字符数组
char message[]=“hello”;
尽管它看上去有点像字符串常量,但是它并不是,它只是前例的初始化列表的一种写法。
一个字符串常量在用于初始化一个字符数组时,它是一个初始化列表,在其它任何情况下,他都是一个字符串常量
注意区分

char message1[] = “hello”; 

//message1是个数组,message1也是一个常量指针,不能改变message1的指向,”hello”是数组的初始化列表,可以通过下标或者间接操作来改变值

char *message2 = “hello”; 

//message2指向字符串常量,message2是一个变量指针,可以改变message2的指向。不能通过下标或者间接操作来改变值。如果硬要改变的话是编译通过但运行出错

5.指向数组的指针
int matrix[3][10];
matrix可以看作成是一个一维数组,它包含3个元素,每个元素是包含10个整形元素的数组(这个是在人看来的,对计算机而言matrix就是个指针,
计算机没有数组的概念,它只懂得指针,数组和下标提出来只不过是方便人理解,这是我到目前为止的看法)。(如同df
-h)
matrix:一个常量指针,指向它的第一个元素,所以matrix是一个指向包含10个整形元素的数组的指针
matrix+1:仍然是一个指针,在matrix的地址的基础上向后移了4*10=40个字节。但是这里不是matrix[1],maxtrix[1]相当于*(matrix+1),再次强调下标和间接操作是一样的。
matrix[0]和
*matrix:maxtrix是一个指向数组的指针,那么*maxtrix就是一个数组,包含(*maxtrix)[0]到(*matrix)[9]这
么10个元素,由于数组名是第一个元素的地址,所以*matrix相当于&(*matrix)[0]也就是&matrix[0][0],
这是一个指向整数的指针。
*(*(matrix+1)+1):有了前面的基础,这个就相当简单了,matrix[1][1]。
但是很有意思的是matrix和matrix[0]的值竟然是一样的,都是&matrix[0][0],换句话说&matrix[0]和matrix[0]是一样的(这块我暂时不能解释,以后解决了再说)

 #include<stdio.h>
 int main(int argc,char **argv)
 {
     int matrix[3][10]={
         {1,2,3,4,5,6,7,8,9,10},
         {10,9,8,7,6,5,4,3,2,1},
         {5,4,3,2,1,6,7,8,9,10}
     };
     printf(“%pt%pn”,matrix,matrix[0]);
     printf(“%pt%pn”,matrix+1,matrix[1]);
     printf(“%pt%pn”,matrix+2,matrix[2]);
     return 0;
}

 //结果

 0x7ffff4609f50  0x7ffff4609f50
 0x7ffff4609f78  0x7ffff4609f78
 0x7ffff4609fa0  0x7ffff4609fa0

我们发现下面的都比上面的多出4*10=40个字节的地址
那么指向数组的指针怎么表示呢
int (*p)[10]=maxtrix;
看一下怎么使用

int a[10];
int (*pa)[10] = &a;
由于对于数组来说&a和a的值是一样的,所以也可以写成
int(*pa)[10]=a;//但是这样写在gcc上会得到一个warning,所以还是不要这样写的好

值虽然一样但是类型不一样,这点很重要。

那么int *pa=a;和int
(*pa)[10]=&a;有什么区别呢
这两个pa的值虽然是一样的,但是类型不一样,还是这句话,第一个pa指向的是一个整数,第二个pa指向的是一个数组,第一个++pa的步长是4,第二个++pa的步长是40
?
int a1[3];
int a2[2][3];
int (*ap)[3];
ap=&a1;
ap=a2;
 用法也不一样
int a[10]={1,2};
int (*pa)[10]=&a;
int *pb=a;
printf(“%pt%pt%pt%pn”,pa,pb,a,&a);
printf(“%dt%dn”,(*pa)[1],pb[1]);//很奇怪,其实声明已经很清除了(*pa)[10]这样才得到一个int,pa[1]编译器显示是int
*类型
输出:
  0x7fffa745c2c0  0x7fffa745c2c0  0x7fffa745c2c0  0x7fffa745c2c0
2       2

这个声明看起来比我们见到过的所有声明都复杂,但事实上并不是很难。你只要假定它是一个表达式,并对它求值。下标引用的优先级高于间接访问,但由于括号的
存在,首先执行的还是间接访问,所以p是一个指针,那么它指向什么呢?接下来是下标引用,所以它指向的是某种类型的数组(包含10个元素),这个表达式没
有更多的操作,所以p是一个指向整形数组的指针。
那么上面matrix的类型是 int (*)[10],而matrix[0]的类型是int *

这里讲一句题外话,数组不能整体赋值给另外一个数组,只能一个一个元素赋值

6.指针数组
注意和上面的指向数组的指针区别
int *p[10]
下标引用的优先级高于间接访问,首先执行下标引用,因此p是某种类型的数组(它包含的元素数为10)。在取得一个值以后,进行了间接访问操作,这个表达式
不再有其它操作,得到的是一个int型。总结一下:对数组的某个元素进行间接操作后得到了一个int型,所以p是一个数组,它包含的元素是指向整型的指
针。
?
#include<stdio.h>
int main(void)
{
    const char *keyword_table[5]={
        “do”,
        “while”,
        “if”,
        “else”,
        “switch”
    };
   
printf(“%pt%pt%pt%pt%pt%pt%pt%cn”,&keyword_table,keyword_table,&keyword_table[0],&”do”,”do”,keyword_table[0],&keyword_table[0][0],*keyword_table[0]); 
    return 0;
}
输出:
0x7fff46c5f790  0x7fff46c5f790  0x7fff46c5f790  0x4006ac        0x4006ac
       0x4006ac        0x4006ac        d