指针初步学习

指针初步学习

1.指针是什么?

电脑内存这么大我们怎么管理?
于是我们创造了指针。

  • 指针是内存最小单位的一个地址

假设以下一格为一个字节(Byte)
类比为房间,如何才能找到每个房间,于是就进行编号。

编号 内存单元
1
2
3

这个编号为内存地址,即为指针。

假设我们要对int a取地址,int大小为4个字节,C语言就会取出第一个字节的地址。

如:

编号(本质为二进制但是用16进制展示) 内存单元
0x00dbfd98 a
0x00dbfd99 a
0x00dbfd9a a
0x00dbfd9b a

此处&a = 0x00dbfd98

但是注意:我们在口头中所说指针一般为C语言的指针变量。

1
2
3
4
int a = 10;
int* pa = &a;
//一般我们在这里就把pa这个指针变量说成指针
//本文中我会区分指针与指针变量。

在不同的机器上,指针长度不同,32位即32bit,能管理4GB的内存(二进制:11111111 11111111 11111111 11111111),所以在32位机器上一个指针变量大小为4字节。

2.指针和指针类型

1
2
3
4
char*   pc = NULL;
short* ps = NULL;
int* pi = NULL;
double* pd = NULL;

这些不同类型的指针变量在32位下都是4个字节,
那么为什么要区分这些不同类型的指针呢?

2.1指针类型的意义

举例1:

1
2
3
int a = 0x11223344;
char* pc = (char*)&a;
*pc = 0;

此时a被修改为了0x11223300。

所以指针类型决定了指针在被解引用时访问几个字节,如果是char*在解引用是访问1个字节,导致了例子中的情况。

举例2:

1
2
3
4
5
6
7
int   a = 0x11223344;

char* pc = (char*)&a;
int* pi = &a;

pc+1;//这里加1会给地址加1个字节
pi+1;//这里加1会给地址加4个字节

即根据指针变量类型的不同进行地址的操作。

那么int*float*可以通用吗?
显然不可以,在解引用时对于内存的操作仍是不同的。

3.野指针

3.1什么是野指针?

定义:指针指向的位置是不可知的。

举例:

1
2
int* p ;
*p = 10;

此处p没有初始化,意味着没有明确的指向(即不初始化放的是随机值)这里的p就是野指针。

此外还有:

  • 指针越界访问(如访问超出数组长度的地址)
  • 指针指向的空间释放(如函数返回一个指针后被销毁)

3.2如何避免野指针的出现。

  • 对指针明确初始化(或初始化为NULL,但此时无法解引用)。
    1
    2
    3
    4
    5
    6
    //以下为一种安全的初始化方式:
    int* p = NULL;
    if (p3 != NULL)
    {
    *p3 = 100;
    }
  • 避免越界
  • 避免局部变量的指针
  • 使用前检查指针的有效性

4.指针运算

4.1指针+-整数

举例:

1
2
3
4
5
6
7
#define N_VALUES 5
float values[N_VALUES];
float *vp;
for(vp = &values[0]; vp < &values[N_VALUES];)
{
*vp++;
}

注意:此处*vp++拆分为*vp;vp++;

4.2指针-指针

1
2
3
int arr[10] = {0};
printf("%d\n",&arr[9] - &arr[0]);
//结果为9

指针减去指针得到的是指针之间元素的个数。但不是所有的指针都能相减,只有指向同一块空间的指针才能相减,才有意义。

4.2.1用法

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int my_strlen(char* str)
{
char* start = str;
while (*str != '\0')
{
str++;
}
return (str - start);
}

int main()
{
int len = my_strlen("abcdef");
printf("%d\n",len);
return 0;
}

但是有没有指针+指针呢?
有,但是无意义。类比于生活中的日期加日期,无意义。

4.3指针的关系运算

  • 其实就是比较大小

举例:

1
2
3
4
5
6
7
#define N_VALUES 5
float values[N_VALUES];
float *vp;
for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{
*vp = 0;
}

以上代码可以通过编译,但是标准不规定其可行,因为N_VALUES-1访问了数组前的内存是不推荐的(但是可以访问数组后,即数组越界只允许往后越界)。

5.指针与数组

  • 数组是一组相同类型元素的集合
  • 指针变量是一个变量,存放的是地址
1
2
3
4
5
6
7
int main()
{
int arr[10] = {0};
int* p =arr;
//p为首元素地址
//联系就是数组名
}

指针初步学习
http://jiangno.com/2024/08/25/note/
作者
江の
发布于
2024年8月25日
许可协议