手记

关于指针

简介

  • c语言之所以强大,以及其自由性,很大部分体现在其灵活的指针运用上。因此,说指针是c语言的灵魂,一点都不为过。

一级指针

* 数组做函数参数时没有副本机制,只是一个地址,因此传入数组参数时需要传入数组的大小

void fun(char str[][5], int len)
{
    printf("sizeof str: %d\n", sizeof(str));    for(int i = 0; i < len; ++i)
    {
        printf("strlen str[%d]: %d\tsizeof str[%d]: %d\n", i, strlen(str[i]), i, sizeof(str[i]));
    }
}

输出结果:
sizeof str: 4循环输出的strlen为每个字符串的长度
循环输出的sizeof为5(原因见函数实参类型)

* 函数改变外部变量

void modifyvariable(int *src, int value)
{
    *src = value;
}

int main()
{
    int a = 100;
    printf("a: %d\n", a);
    modifyvariable(&a, 200);
    printf("a: %d\n", a);
}

输出结果:
a: 100a: 200

* 跨进程改变变量(外挂)

* 采用微软的`detours`库

* 将程序编译成动态链接库DLL

* 将DLL注入到目标线程中,实现修改某地址的数据,或者拦截函数

* 做函数形参,数组做参数时会退化为一个一级指针,即其内存空间大小为4

void fun(char str[][5], int len)
{
    printf("sizeof str: %d\n", sizeof(str));
}
输出结果:
sizeof str: 4

* 储存数组的首地址,指针数组

char str[][6] = { "eth8", "eth1", "eth6", "eth3", "eth4" };
char *pstr[5] = { NULL, NULL, NULL, NULL, NULL };for (int i = 0; i < 5; ++i)
{
    pstr[i] = str[i];
}

char *p = NULL;for (int i = 1; i < 5; ++i)
{    for (int j = 0; j < i; ++j)
    {        if (strcmp(pstr[i], pstr[j]) < 0)
        {
            p = pstr[i];
            pstr[i] = pstr[j];
            pstr[j] = p;
        }
    }
}for (int i = 0; i < 5; ++i)
{
    printf("%s\n", pstr[i]);
}

输出结果:
eth1
eth3
eth4
eth6
eth8

* return 有副本机制

* 其值存放在寄存器中,不能取地址

* 如果返回一个在栈上声明的变量,两次输出return的值可能不同

* 如果立马输出,由于寄存器还未被其他变量使用,则可能返回正确值;

* 如果延时输出(几条IO输出语句即可),则返回错误值;

* 作为函数的返回地址(不能返回指向栈上的内容)

* 具体原因见上一条

* 存储常量字符串的首地址,不能修改其值

* 间接访问结构体,创建堆上的变量

* 通过`->`运算符访问结构体中声明的变量

* 通过`malloc`、`calloc`、`realloc`、`new`等函数在堆上开辟内存空间

* #的作用,无论类型,直接加"",可用于获取函数名变量名等

#define funname(fun)    \
{           \
    printf("%s\n", #fun);       \
}void modifyvariable(int *src, int value)
{
    *src = value;
}
int main()
{
    funname(modifyvariable);    return 0;
}
输出结果:
modifyvariable

指针数组

  • 批量管理地址

char str[][6] = { "eth8", "eth1", "eth6", "eth3", "eth4" };
char *pstr[5] = { NULL, NULL, NULL, NULL, NULL };for (int i = 0; i < 5; ++i)
{
    pstr[i] = str[i];
}

char *p = NULL;for (int i = 1; i < 5; ++i)
{    for (int j = 0; j < i; ++j)
    {        if (strcmp(pstr[i], pstr[j]) < 0)
        {
            p = pstr[i];
            pstr[i] = pstr[j];
            pstr[j] = p;
        }
    }
}for (int i = 0; i < 5; ++i)
{
    printf("%s\n", pstr[i]);
}

输出结果:
eth1
eth3
eth4
eth6
eth8

函数指针

  • 函数名等价于常指针

  • 函数指针数组:int (*p[2])(int a, int b) = {add, sub};

int add(int x, int y)
{    return x + y;
}

int sub(int x, int y)
{    return x - y;
}

int main()
{
    int(*fun[2])(int, int) = { add, sub };    for (int i = 0; i < 2; ++i)
    {
        printf("%d\n", fun[i](100, 50));
    }    return 0;
}
输出结果:15050

malloc,realloc,calloc

  • malloccalloc区别:

    • eg: int *p = (int *)calloc(10, sizeof(int));

    • eg: int *p = (int *)malloc(sizeof(int) * 10);

    • malloc在堆上开辟一块内存,不会对内存进行清零操作

    • calloc在堆上开辟一块内存,并且执行内存清零操作

  • realloc重新分配内存,新增加的内存不会置零

关于指针类型

  • 根据指针的内存大小来判定指针的类型

void getaddress(char str[][6])
{
    printf("In Function: \n");
    printf("str:\t\t%p\tsizeof: %d\n", str, sizeof(str));
    printf("str[0]:\t\t%p\tsizeof: %d\n", str[0], sizeof(str[0]));
    printf("str[0][0]:\t%p\tsizeof: %d\n", &str[0][0], sizeof(str[0][0]));
}

int main()
{
    char str[][6] = { "eth8", "eth1", "eth6", "eth3", "eth4" };
    {
        printf("In Main: \n");
        printf("str:\t\t%p\tsizeof: %d\n", str, sizeof(str));
        printf("str[0]:\t\t%p\tsizeof: %d\n", str[0], sizeof(str[0]));
        printf("str[0][0]:\t%p\tsizeof: %d\n", &str[0][0], sizeof(str[0][0]));
    }
    getaddress(str);    return 0;
}

输出结果:
In Main:
str:            0043FC04        sizeof: 30str[0]:         0043FC04        sizeof: 6str[0][0]:      0043FC04        sizeof: 1In Function:
str:            0043FC04        sizeof: 4str[0]:         0043FC04        sizeof: 6str[0][0]:      0043FC04        sizeof: 1

关于指针的遍历

  • 无论多少级指针,其遍历方法都类似

int main()
{
    int num[4][3] = { {1, 2, 3}, {2, 3, 4}, { 3, 4, 5}, {4, 5, 6} };    for (int i = 0; i < 4; ++i)
    {        for (int j = 0; j < 3; ++j)
        {
            printf("%d\t", num[i][j]);
        }
        putchar('\n');
    }

    putchar('\n');
    putchar('\n');    for (int i = 0; i < 4; ++i)
    {        for (int j = 0; j < 3; ++j)
        {
            printf("%d\t", *(*(num + i) + j));
        }
        putchar('\n');
    }    return 0;
}
输出结果:1       2       32       3       43       4       54       5       61       2       32       3       43       4       54       5       6

NOTE

  • printf不会进行类型转换,即占位符是什么类型,就按什么类型输出



作者:silverlaw
链接:https://www.jianshu.com/p/d0c1faefe961


0人推荐
随时随地看视频
慕课网APP