关于指针

作者: silverlaw | 来源:发表于2018-09-10 21:08 被阅读4次

简介

  • 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: 100
a: 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;
}
输出结果:
150
50

malloc,realloc,calloc

  • malloccalloc区别:
    • malloc在堆上开辟一块内存,不会对内存进行清零操作
      • eg: int *p = (int *)malloc(sizeof(int) * 10);
    • calloc在堆上开辟一块内存,并且执行内存清零操作
      • eg: int *p = (int *)calloc(10, sizeof(int));
  • 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: 30
str[0]:         0043FC04        sizeof: 6
str[0][0]:      0043FC04        sizeof: 1
In Function:
str:            0043FC04        sizeof: 4
str[0]:         0043FC04        sizeof: 6
str[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       3
2       3       4
3       4       5
4       5       6


1       2       3
2       3       4
3       4       5
4       5       6

NOTE

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

相关文章

  • C:函数指针的坑

    关于该死的函数指针和指针函数 先来个目录 常量指针、指针常量 数组指针、指针数组 函数指针、指针函数 1、先看第一...

  • C++对象模型(2)

    本文预览: 关于vptr(虚函数表指针)和vtbl(虚函数表) 关于this指针 关于Dynamic Bindin...

  • 关于指针

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

  • 关于指针

    本文为学习使用 在C语言中任意的同类型指针都可以比较大小指针变量是一个表示[内存地址]的长整数而已,当然可以比较。...

  • 关于指针

    今天认真分析了下指针,有一些感悟:函数传递参数,只有传地址才能更改对应参数的值。按照上面的原理,我们如果想要更改的...

  • 关于指针

    《POINTERS ON C》一书总结指针以下方面:指针基础警告总结编程提示 指针基础的总结 计算机内存中的每一个...

  • 关于指针

    关于指针 1. 程序对变量的读写操作,实际上是对变量所在的存储空间进行写入或取出数据。 2. 通过变量名引用变量,...

  • 关于指针传递和指针的指针

    一开始没有理解,导致对这个概念非常的模糊和不解。最近看完《 彻底搞定C语言指针详解》,里面关于指针的指针的解释有了...

  • c语言的指针

    关于指针 指针就是地址,凡是出现“指针”的地方,都可以用“地址”代替,例如,变量的指针就是变量的地址,指针变量就是...

  • void 和 void*

    void指针是什么? void指针一般被称为通用指针或泛指针,它是C关于“纯粹地址(raw address)”的一...

网友评论

    本文标题:关于指针

    本文链接:https://www.haomeiwen.com/subject/unyegftx.html