C 指针概要

简单罗列一下 ANSI C 的指针用法,便于复习。

1. 指针常量

指针常量意指 "类型为指针的常量",初始化后不能被修改,固定指向某个内存地址。我们无法修改指针自身的值,但可以修改指针所指目标的内容。

int x[] = { 1, 2, 3, 4 };
int* const p = x;

int i = 0;
for (i = 0; i < 4; i++)
{
    int v = *(p + i);
    *(p + i) = ++v;

    printf("%d/n", v);

    //p++;  // Compile Error!                                                             
}


上例中的指针 p 始终指向数组 x 的第一个元素,和数组名 x 作用相同。由于指针本身是常量,自然无法执行 "p++"、"++p" 之类的操作,否则会导致编译错误。

2. 常量指针

常量指针是说 "指向常量数据的指针",指针目标被当做常量处理(尽管原目标不一定是常量),不能用通过指针做赋值处理。指针自身并非常量,可以指向其他位置,但依然不能做赋值操作。

int x = 1, y = 2;

int const* p = &x;
//*p = 100; // Compile Error!

p = &y;
printf("%d/n", *p);

//*p = 100; // Compile Error!


建议常量指针将 const 写在前面更易识别。

const int* p = &x;


看几种特殊情况:

(1) 下面的代码据说在 VC 下无法编译,但 GCC 是可以的。

const int x = 1;
int* p = &x;

printf("%d/n", *p);

*p = 1234;                                                                               
printf("%d/n", *p);


(2) const int* p 指向 const int 自然没有问题,但肯定也不能通过指针做出修改。

const int x = 1;
const int* p = &x;

printf("%d/n", *p);

*p = 1234;  // Compile Error!


(3) 声明指向常量的常量指针,这很罕见,但也好理解。

int x = 10;
const int* const p = &i;

p++; // Compile Error!
*p = 20;  // Compile Error!


区别 "指针常量" 和 "常量指针" 方法很简单:看 const 要修饰的是谁,也就是 "*" 在 const 的左边还是右边。

  • int* const p: const 修饰指针变量(p),指针是常量。
  • int const *p: const 修饰指针所指向的内容(*p),是常量的指针。在函数参数里通常写成 "const int *p",都表示目标数据是常量。
  • const int* const p: 指向常量的指针常量。右边的 const 指明 p 指针为常量,左边的 const 表明 "int *p" (目标数据)为常量。

3. 指针的指针

指针本身也是内存区的一个数据变量,自然也可以用其他的指针来指向它。

int x = 10;
int* p = &x;
int** p2 = &p;

printf("p = %p, *p = %d/n", p, *p);
printf("p2 = %p, *p2 = %x/n", p2, *p2);                                                  
printf("x = %d, %d/n",*p, **p2);


输出:

p = 0xbfba3e5c, *p = 10
p2 = 0xbfba3e58, *p2 = bfba3e5c
x = 10, 10


我们可以发现 p2 存储的是指针 p 的地址。因此才有了指针的指针一说。

4. 数组指针

默认情况下,数组名为指向该数组第一个元素的指针常量。

int x[] = { 1, 2, 3, 4 };
int* p = x;

int i;
for (i = 0; i < 4; i++)
{
    printf("%d, %d, %d/n", x[i], *(x + i), , *p++);                                        
}


尽管我们可以用 *(x + 1) 访问数组元素,但不能执行 x++ / ++x 操作。

但 "数组的指针" 和数组名并不是一个类型,数组指针将整个数组当做一个 "对象",而不是其中的成员(元素)。

int x[] = { 1, 2, 3, 4 };                                                                

int* p = x;
int (*p2)[] = &x; // 数组指针

int i = 0;
for(i = 0; i < 4; i++)
{
    printf("%d, %d/n", *p++, (*p2)[i]);
}


更多详情参考《C 指针: 数组指针》

5. 指针数组

元素类型为指针的数组称之为指针数组。

int x[] = { 1, 2, 3, 4 };
int* ps[] = { x, x + 1, x + 2, x + 3 };

int i = 0;
for(i = 0; i < 4; i++)
{
    printf("%d/n", *(ps[i]));                                                            
}


x 默认就是指向第一个元素的指针,那么 x + n 自然获取后续元素的指针。

指针数组通常用来处理交错数组(Jagged Array,又称 "数组的数组",不是 "二维数组"),最常见的就是字符串数组了。

void test(const char** x, int len)
{
    int i;
    for (i = 0; i < len; i++)
    {
        printf("test: %d = %s/n", i, *(x + i));
    }
}

int main(int argc, char* argv[])
{
    char* a = "aaa";
    char* b = "bbb";

    char* ss[] = { a, b };

    int i;
    for (i = 0; i < 2; i++)
    {
        printf("%d = %s/n", i, ss[i]);
    }

    // ----------------

    test(ss, 2);

    return EXIT_SUCCESS;
}


更多详情参考《C 指针: 指针数组》

6. 函数指针

默认情况下,函数名就是指向该函数的指针常量。

void inc(int* x)
{
    *x += 1;
}

int main(void)
{
    void (*f)(int*) = inc;

    int i = 100;
    f(&i);
    printf("%d/n", i);                                                                       

    return 0;
}


如果嫌函数指针的声明不好看,可以像 C# 委托那样定义一个函数指针类型。

typedef void (*Inc)(int*);                                                                   

int main(void)
{
    Inc f = inc;
    ... ...
}


很显然,有了 typedef,下面的代码更易阅读和理解。

Inc getFunc()
{
    return inc;
}

int main(void)
{
    Inc inc = getFunc();                                                                     
    ... ...
}


注意:

(1) "typedef void (*Inc)(int*); " 定义函数指针类型。
(2) "typedef void (Inc)(int*); " 定义函数类型。

void test()
{
    printf("test");
}

typedef void(func)();
typedef void(*funcptr)();

int main(int argc, char* argv[])
{
    func* f = test;
    funcptr p = test;

    f();
    p();

    return EXIT_SUCCESS;
}


----------- 分割线 --------------

不同书上的 "常量指针" 和 "指针常量" 是个糊涂说法。"指针常量" 可以理解为 "指针是常量",而 "常量指针" 也可以当做 "常量类型的指针",似乎是一个意思。网上相关文章和回答也是乱七八糟的,缺乏统一的口径,还得自己多多注意。 [sweat]

 

 

 

 

原文网址:http://www.rainsts.net/article.asp?id=893

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值