C-认识指针

认识指针

内容来自《深入理解C指针》

声明指针
在数据类型后面跟上星号*,如下的声明都是等价的

int* pi;
int * pi;
int *pi;
int*pi;

阅读声明
如下:

const int *pci;

1.pci是一个变量 const int *pci;
2.pci是一个指针变量 const int *pci;
3.pci是一个指向整数的指针变量 const int *pci;
4.pci是一个指向整数常量的指针变量 const int *pci;

地址操作符
地址操作符&会返回操作数的地址

int num;
int *pi = #

打印指针的值

int num = 0;
int *pi = #
printf("Address of num: %p Value: %d\n", &num, num);
printf("Address of pi: %p Value: %p\n", &pi, pi);

输出可能如下:

Address of num: 0x7ffeefbff51c Value: 0
Address of pi: 0x7ffeefbff510 Value: 0x7ffeefbff51c

在不同的平台上用一致的方式显示指针的值比较困难。一种方法是把指针转换为void指针,然后使用%p格式说明符来显示:

printf("Value of pi: %p\n", (void *)pi);

间接引用操作符
间接引用操作符(*)返回指针变量指向的值

间接引用操作符
NULL
NULL被赋值给指针就意味着指针不指向任何东西
NULL宏是强制类型转换为void指针的整数常量0,在很多库中的定义如下:

#define NULL ((void *)0)

测试指针是否设置为NULL。如果pi被赋值为NULL值,那就会被解释为二进制0

pi = NULL;
if (pi) {
    
    
    printf("pi is null\n");
} else {
    
    
    printf("pi is not null\n");
}

或者

if (pi == NULL) {
    
    }
if (pi != NULL) {
    
    }

void指针

void指针是通用指针,用来存放任何数据类型的引用

void *pv;

任何指针都可以被赋给void指针,它可以被转换回原来的指针类型,指针的值和原指针的值是相等的

int num = 100;
int *pi = #
printf("Value of pi: %p\n", pi);
void *pv = pi;
pi = (int *)pv;
printf("Value of pi: %p\n", pi);

输出如下,显示指针地址是一样的:

Value of pi: 0x7ffeefbff51c
Value of pi: 0x7ffeefbff51c

void指针只能用做数据指针,而不能用做函数指针

sizeof操作符可以用在void指针上

size_t size = sizeof(void *);

size_t 是用来表示长度的数据类型

全局和静态指针

指针被声明为全局或静态,就会在程序启动时被初始化为NULL

int *globalpi;

void foo() {
    
    
    static int *staticpi;
}

int main(int argc, const char * argv[]) {
    
    
    
    return 0;
}

全局和静态指针
size_t

size_t类型表示C中任何对象所能达到的最大长度。是无符号整型,负数在这里没有意义
size_t用做sizeof操作符的返回值类型,同时也是很多函数的参数类型,如mallocstrlen
size_t的典型定义如下:
size_t

size_t推荐的格式说明符是%zu

size_t sizet = 5;
printf("%d\n", sizet);
printf("%zu\n", sizet);

sizeof操作符可以用来判断指针的长度

printf("Size of *char: %d\n", sizeof(char *));

intptr_t和uintptr_t

intptr_tuintptr_t用来存放指针的地址。
它们提供了一种可移植且安全的方法声明指针,而且和系统中使用的指针长度相同,对于把指针转化成整数形式来说很有用
uintptr_tintptr_t的无符号版本

intptr_t和uintptr_t

指针操作

给指针加上整数

给指针加上一个整数实际上加的数是这个整数和指针数据类型对应字节数的乘积

    int vector[] = {
    
    28, 41, 7};
    int *pi = vector;
    
    printf("%d\n", *pi); //28
    pi += 1;
    printf("%d\n", *pi); //41
    pi += 1;
    printf("%d\n", *pi); //7

这里的数组名字vector,是数组的地址,也是数组第一个元素的地址

从指针减去整数

和加法类似,减去整数时,地址值会减去数据类型的长度和整数值的乘积

    int vector[] = {
    
    28, 41, 7};
    int *pi = vector + 2;
    
    printf("%d\n", *pi); //7
    pi -= 1;
    printf("%d\n", *pi); //41
    pi -= 1;
    printf("%d\n", *pi); //28

指针相减

指针相减的差值通常没什么用,但可以判断数组中的元素顺序

ptrdiff_t类型表示指针差值的可移植方式

指针相减

指针的常见用法

多层间接引用

把变量声明为指针的指针,有时称之为双重指针

#include <stdio.h>

int main(int argc, const char * argv[]) {
    
    
    
    char *titles[] = {
    
    "A Tale of Two Cities",
        "Wuthering Heights",
        "Don Quixote",
        "Odyssey",
        "Moby Dick",
        "Hamlet",
        "Gulliver's Travels"
    };
    char **bestBooks[3];
    char **englishBooks[4];
    
    bestBooks[0] = &titles[0];
    bestBooks[1] = &titles[3];
    bestBooks[2] = &titles[5];
    
    englishBooks[0] = &titles[0];
    englishBooks[1] = &titles[1];
    englishBooks[2] = &titles[5];
    englishBooks[3] = &titles[6];
    
    printf("%s\n", *englishBooks[1]); //Wuthering Heights
    
    return 0;
}

如下的声明:

    char **bestBooks[3];
    char **englishBooks[4];

两个数组都声明为字符指针的指针。每个数组元素包含一个指向char指针的指针

本例的内存分配如下:
多层间接引用

常量和指针

指向常量的指针

将指针定义为指向常量,意味着不能通过指针修改它所引用的值,但可以改变指针

指向常量的指针
如下的语句是等价的:

const int *pci
int const *pci

指向非常量的常量指针

指向非常量的常量指针意味指针不可变,但它指向的数据可变

指向非常量的常量指针

指向常量的常量指针

这种指针本身不能修改,指向的数据也不能通过它来修改

const int * const pci = &num;

指向常量的常量指针

指向“指向常量的常量指针”的指针

指向常量的指针也可以有多层间接引用

    int num = 100;
    const int * const pci = &num;
    const int * const *pcpci;
    
    printf("%d\n", *pci); //100
    pcpci = &pci;
    printf("%d\n", **pcpci); //100

猜你喜欢

转载自blog.csdn.net/u014084081/article/details/130730328
C-