C的存储器和指针

指针

存储器中某条数据的地址(用于保存存储器地址的变量)

目的

避免副本
共享数据

存储器

计算机系统中的记忆设备,用来存放程序和数据
它分为(低位到高位):
    代码块
        一般会放置在存储器地址的低位。它是只读的,是存储器用来加载机器代码的部分

    常量段
        程序一开始运行时创建,但保存在只读存储器中。它是程序中用到的不变量

    全局量
        定义在函数之外,对所有函数可见。程序一开始运行就会创建全局量,可以修改他们

    堆
        用于动态存储:程序在运行时创建一些数据,然后使用很长一段时间

    栈
        存储器用来保存局部变量的部分。每当调用函数,函数的所有局部变量都在栈上创建。它之所有叫栈是 因为它看起来就像堆积而成的栈板:当进入函数时,变量会放到栈顶;当离开函数时,把变量从栈顶拿走。它从存储器的顶部开始,向下增长。

如何找出变量在存储器中的指针(使用&运算符)

#include <stdio.h>

int main()
{
    int point = 4;
    /*
        %p用于打印指针
    */
    printf("point的指针位置是:%p\n", &point);
    return 0;
}

如何读取指针中的内容(使用*运算符)

#include <stdio.h>

int main()
{
    int  c = 10;
    /*
        获取变量c的指针地址 &运算符
        注意需要用int *申明指针变量
    */
    int *point = &c;
    /*
        获取指针地址对应的值 *运算符
    */
    int val = *point;
    printf("指针是%p\n", &c);
    printf("指针对应的值是%d\n", val);
}

改变地址中的内容

#include <stdio.h>

int main()
{
    int c = 10;
    int *point = &c;
    int val = *point;
    *point = 99;
    printf("改变后的c的值为%d", c);
}

数组和函数中的指针变量

#include <stdio.h>

void size(char str[])
{
    printf("传入的字符串是%s\n", str);

    /*
        如果函数参数申明为数组类型,他会被当做指针处理,因此sizeof得到的值是8(64为系统,sizeof(* int))
    */
    printf("字符串的长度是:%i\n", sizeof(str));
    char str_size[] = "this is demo";
    char * point = *str_size;

    /*
        sizeof直接传入数组依然计算的是数组的长度
    */
    printf("数组变量的长度是:%i\n", sizeof(str_size));

    printf("数组变量指针的长度是:%i\n", sizeof(point));

    /*
        数组变量可以用作指针
    */
    printf("数组的变量的地址是:%s\n", &str_size);

    /*
        数组变量指向数组的第一个值
    */
    printf("数组指针变量的地址是:%s\n", &point);
    *point = "test";

    /*
        编译不能通过,数组变量不能指向其他地方
    */
    printf("指针变量被赋值了吗?%s\n", point);
}


int main()
{
    size("test");
}

为什么数组变量不能指向其他地方?

当创建指针变量时,计算机会分配4或8个字节的存储空间。如果创建的是数组,计算机会为数组分配存储空间,但不会为数组变量分配任何空间,编译器仅在出现它的地方把它替换成数组的起始地址

对于数组取值的两种方式

#include <stdio.h>

int main()
{
    char str[] = "this is arr";
    printf("看看结果%c\n", str[3]);
    printf("另外一种方式看看结果%c\n", *(str+3));

    int nums[] = {1,2,3};
    printf("看看结果%i\n", nums[2]);
    printf("另外一种方式看看结果%i\n", *(nums+2));
    return 0;
}

1.arr[i]
2.*(arr+i)

指针为什么需要有类型?

#include <stdio.h>

int main()
{
    int nums[] = {1,2,3};

    /*
        两个地址相隔四个字节(注意是16进制)
    */
    printf("看看第一个元素的位置%p\n", nums);
    printf("看看第二个元素的位置%p\n", nums+1);
    return 0;
}
因为对于char指针加1,指针会指向存储器的下一个地址,因为char就占1字节
int通常占四个字节,如果int指针加1,编译后的代码就会对存储器加4

指针输入数据

scanf
fgets

scanf

#include <stdio.h>
int main()
{
    /*
        输入字符串
    */
    char test[20];
    scanf("%19s", test);
    printf("输入的字符串为:%s\n", test);

    /*
        输入数字
    */
    int t;
    scanf("%i", &t);
    printf("输入的数字是%i\n", t);
}

为什么数组传入变量名就可以,数字需要传'&'呢?
scanf和函数一样,传入数组的变量名会当做指针使用,它会根据指针去修改对应的值

为什么scanf的时候需要指定'%19s'?
如果不指定scanf读取的长度,当用户输入的值超过test数组的长度的时候会导致内存溢出。因此一般指定scanf的长度为test长度减1(去掉一个结束字符'\0')

fgets

#include <stdio.h>
int main()
{
    char str[4];
    /*
        此处需要注意的是str是数组变量,所以传入的是str不是* str
    */
    fgets(str, sizeof(str), stdin);
    printf("输入的字符为%s\n", str);
}

scanf和fgets

1.scanf记得在格式串中加入限制长度,sacnf就能限制用户输入长度(没有强制要求),并且输入的字符长度需要减去结束符的长度,fgets强制限制用户输入字符数
2.scanf允许输入多个字段,而且能指定结构化数据根据什么字符划分。fgets只允许缓冲区输入一个字符串,而且只能是字符串,不能是其他数据类型
3.sanf不能输入空格,遇到空格就会停止读取。fget可以输入空格

字符串创建的过程

1.载入字符串字面值(也就是在常量(只读)中定义字面值)
2.在栈上新建一个数组,主要会分配数组的存储块大小
3.初始化数组,把字符串字面值复制到栈(可修改)上
坚持原创技术分享,您的支持将鼓励我继续创作!