配套代码笔记仓库

目录

指针

变量与地址

int i=100;

i是变量名,也就是地址。

100是存放在这个地址的变量的值。

指针与指针变量

int   i = 100;
int  *p = &i;
int **q = &p;

p是一个指针变量,他所存放的值是指针,指向另一个变量i的地址。

直接访问与间接访问

同样对于上面那个存放值为100的变量,既可以通过i直接访问,也可以通过*p, **q来间接访问。

#include <stdio.h>
#include <stdlib.h>



int main()
{
    int i = 1;

    int *p = &i;
    // 相当于
    // int *p;
    // p = &i;

    int **q = &p;

    printf("i = %d\n", i);
    printf("&i = %d\n", &i);

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

    printf("q = %d\n", q);
    printf("*q = %d\n", *q);
    printf("**q = %d\n", **q);
    // i = 1
    // &i = 1175115956
    // p = 1175115956
    // &p = 1175115944
    // *p = 1
    // q = 1175115944
    // *q = 1175115956
    // **q = 1

#if 0
    float  *q;
    double *d;
    char   *c;

    printf("%d\n", sizeof(i));
    printf("%d\n", sizeof(p));
    printf("%d\n", sizeof(q));
    printf("%d\n", sizeof(d));
    printf("%d\n", sizeof(c));
    // out:
    // 4
    // 8
    // 8
    // 8
    // 8
    /* 指针在某一个平台所占的大小是一样的 */
    /* 其指向的类型的空间的大小,由指针的类型决定 */

#endif

#if 0
    printf("i = %d\n", i);
    printf("&i = %d\n", &i);
    printf("p = %d\n", p);
    printf("&p = %d\n", &p);
    printf("*p = %d\n", *p);
    // out:
    // i = 1
    // &i = 1343894748
    // p = 1343894748
    // &p = 1343894736
    // *p = 1
#endif

    exit(0);
}

空指针与野指针

  • 野指针:int *p = 0x14532534,不确定这个地址的情况,盲目的指过去,那么读或者写都是非法的。
  • 空指针:int *p = NULL,避免野指针。
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int *p;

    *p = 1;

    printf("%p --> %d\n", p, *p);
    // 有的编译器报段错误,有的编译器能输出
    // 0x7feb1910dad0 -- > 420327424

    exit(0);
}

空类型

void *q

万能类型。

定义与初始化的书写规则

int *p;
int* p;

指针运算

& * 关系运算 ++ --

指针与数组

指针与一维数组

#include <stdio.h>
#include <stdlib.h>

// TYPE NAME = VALUE;

// a[i]value: a[i] = *(a+i) = *(p+i) = p[i]
// &a[i]: &a[i] = a+i = p+i = &p[i]

int main()
{

    int  a[] = {5, 1, 7, 2, 8, 3};
    int  y;
    int *p = &a[1];

    y = (*--p)++;

    printf("y = %d\n", y);         // out: y = 5
    printf("a[0] = %d\n", a[0]);   // out: a[0] = 6

#if 0
    int *p = (int[3]){1, 2, 3};
    // 只是不要数组名了

    for (int i = 0; i < 3; i++)
    {
        printf("%p --> %d\n", &p[i], p[i]);
    }
    // 0x7ffd12681964 --> 1
    // 0x7ffd12681968 --> 2
    // 0x7ffd1268196c --> 3
#endif

#if 0
    int  a[3];
    int *p = a;
    int  i;

    for (i = 0; i < sizeof(a) / sizeof(*a); i++)
    {
        printf("%p --> %d\n", &a[i], a[i]);
    }

    for (i = 0; i < sizeof(a) / sizeof(*a); i++)
    {
        scanf("%d", p++);
    }

    p = a;
    for (i = 0; i < sizeof(a) / sizeof(*a); i++, p++)
    {
        // printf("%d\n", *p++);
        printf("%p --> %d\n", p, *p);
    }

    // out:
    //
    // 0x7ffdad36c478 --> -563487456
    // 0x7ffdad36c47c --> 32710
    // 0x7ffdad36c480 --> 0
    // 1
    // 2
    // 3
    // 0x7ffdad36c478 --> 1
    // 0x7ffdad36c47c --> 2
    // 0x7ffdad36c480 --> 3
#endif

#if 0
    int a[3] = {1, 2, 3};
    int i;

    int *p = a;

    p++;   // p从a[0]挪到a[1]
    printf("%p,%p\n", p, p + 1);

    // *a相当于*(a+0)相当于a[0]
    // for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
    for (i = 0; i < sizeof(a) / sizeof(*a); i++)
    {
        // printf("%p--> %d\n", &a[i], a[i]);
        // printf("%p--> %d\n", a + i, a[i]);
        printf("%p--> %d\n", p + i, *(p + i));
    }
    printf("\n");
#endif

    exit(0);
}

指针与二维数组

#include <stdio.h>
#include <stdlib.h>



int main()
{
    int  a[2][3] = {1, 2, 3, 4, 5, 6};
    int  i, j;
    int *p     = *a;
    int(*q)[3] = a;


#if 0
    //(W) int *p = a;
    // 报错,不兼容
    // 因为a是行指针,不是int类型指针

    // int *p = *a;
    *p = &a[0][0];

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

#endif

#if 1
    printf("%p %p\n", a, a + 1);
    printf("%p %p\n\n", q, q + 1);

    for (i = 0; i < 2; i++)
    {
        for (j = 0; j < 3; j++)
        {
            // printf("%p --> %d ", &a[i][j], a[i][j]);
            // printf("%p --> %d ", *(a + i) + j, *(*(a + i) + j));
            printf("%p --> %d ", *(q + i) + j, *(*(q + i) + j));
        }

        printf("\n");
    }
#endif

    exit(0);
}

指针与字符数组

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{

    char *str = "hello";

    printf("%d %d\n", sizeof(str), strlen(str));
    // out: 8 5

    //(F) strcpy(str, "world");
    // 这里企图把 "world" 覆盖 "hello"这个串常量

    str = "world";

    puts(str);

    // char str[] = "hello";

    // printf("%d %d\n", sizeof(str), strlen(str));
    // out :6 5



#if 0
    char str[] = "hello";
    // str[6]

    //(F) str = "world";
    strcpy(str, "world");

    puts(str);

#endif



#if 0
    char str[] = "I love china!";

    char *p = str + 7;

    puts(str);
    puts(p);
    // I love china!
    // china!
#endif



    exit(0);
}

const 与指针

  • 常量指针:指向常量的指针

    const修饰*p,指针指向的值不能变

  • 指针常量:这个指针是一个常量

    const修饰指针,指针指向不能变

/**
 *   const int a;
 *   int const a;
 *
 *   常量指针
 *   const int *p;
 *   int const *p;
 *
 *   指针常量
 *   int *const p;
 *
 *   const int *const p;
 *
 */

#include <stdio.h>
#include <stdlib.h>

#define PI 3.14

int main()
{
    int i = 1;
    int j = 100;

    const int *const p = &i;

    //(F) p = &j;

    //(F) *p = 10;


#if 0
    int *const p = &i;

    //(T) *p = 10;

    //(F) p = &j;
    // [main][~/workspace/Linux-C-Notes/Chapter6]$ make const
    // cc     const.c   -o const
    // const.c: In function ‘main’:
    // const.c:29:7: error: assignment of read-only variable ‘p’
    //    29 |     p = &j;
    //       |       ^
    // make: *** [<builtin>: const] Error 1

    printf("i = %d\n", *p);

#endif

#if 0
    int i = 1;
    int j = 2;

    // 常量指针
    const int *p = &i;

    //(T) i = 2;
    // 直接用i改还是可以改成功的

    //(F) *p = 2;

    //(T) p = &j;

    printf("i = %d\n", i);

#endif


#if 0
    const float pi = 3.14;
    // const 将变量常量化,相比于宏,多了检查语法

    //(F) pi = 3.14159;

    // float *p = &pi;
    const float *p = &pi;

    // *p = 3.14159;
    // [main][~/workspace/Linux-C-Notes/Chapter6]$ make const
    // cc     const.c   -o const
    // const.c: In function ‘main’:
    // const.c:28:16: warning: initialization discards ‘const’ qualifier from
    // pointer target type [-Wdiscarded-qualifiers]
    //    28 |     float *p = &pi;
    //       |

#endif

    exit(0);
}

指针数组与数组指针

  • 数组指针:指向数组的指针

    【存储类型】 数据类型 (*指针名)【下标】 = 值

    如:int (*p)[3]; 看成 int[3] *p;

  • 指针数组:

    【存储类型】 数据类型 * 数组名【长度】

    如:int *arr[3]; 看成 int *[3] arr;

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main()
{
    char *name[5] = {"Follow me", "Basic", "Great", "Fortran", "Computer"};
    // 指针数组
    int   i, j, k;
    char *tmp;

    for (i = 0; i < 5 - 1; i++)
    {
        k = i;
        for (j = i + 1; j < 5; j++)
        {
            if (strcmp(name[k], name[j]) > 0)
                k = j;
        }
        if (k != j)
        {
            tmp     = name[i];
            name[i] = name[k];
            name[k] = tmp;
        }
    }

    for (int i = 0; i < 5; i++)
    {
        puts(name[i]);
    }

    exit(0);
}

多级指针