指针初阶(超详细版)

1.指针是什么?

1.指针是内存中一个最小单元的编号,也就是地址

2.平时口语中说的指针,通常指的是指针变量,用来存放内存地址的变量

&a----对a取地址,取出a的地址
a是一个整型变量,整型变量占用四个字节,每个字节都用地址
&a取出的是第一个字节的地址(较小的地址)
int *pa=&a;
pa被称为指针变量是专门用来存放地址的

2.指针和指针类型

 32位机器地址是4个字节,指针变量大小是4个字节

64位机器地址是8个字节,指针变量大小是8个字节

既然指针变量大小是一样的,那为什么要分char *、int *……呢?

①指针类型决定了指针类型解引用的时候一次性访问几个字节

char *的指针解引用的时候访问1个字节

int *的指针解引用的时候访问4个字节

 eg:

 int a=0x11223344;

char *pc=&a;

*pc=0;

则a变成0x00223344

int a=0x11223344;

int *pc=&a;

*pc=0;

则a变成0x00000000

②指针类型决定指针的步长(指针+1到底跳过几个字节)

字符指针+1跳过一个字节

整型指针+1跳过四个字节

指针类型的意义:指针的不同类型,起始提供了不同的视角去观看和访问内存

3.野指针

概念:指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

下面看一段代码:

int  *p;

*p=20; p是一个局部变量,没有初始化,里面的地址是随机值,而把一个随机值地址对应的空间中存放数据是非常危险的

所以使用指针的时候应该有一个明确的指向的

指针的越界访问:

int arr[]={1,2,3,4,5,6,7,8,9,10};

int *p=arr;

int i=0;

for(int i=0;i<=10;i++}

{

printf("%d",*p);

p++;

}

3.指针指向的空间释放

int *test()

{

   int a=10;

return &a;

}

int main()

{

   int *p=test();

printf("%d",*p);

return 0;

}

p指向了a的地址,但在函数返回a的地址后,系统自清除了a地址对应的内容

但是第一次打印还是会

如何规避野指针?

1.指针初始化

如果一开始不知道要让指针指向谁,可以指向空

int *p=NULL;

if(p!=NULL)

{

}

2.小心指针越界

3.指针空间释放时将指针置为空

4.避免返回局部变量的地址

5.使用指针之前要判断有效性(判断不为空)

4.指针运算

*指针+-整数

#define _CRT_SECURE_NO_WARNINGS 1
#define N_VALUES 5
#include
int main()
{
       float values[N_VALUES];
       float* vp;
       for (vp = &values[0]; vp < &values[N_VALUES];)
       {
              *vp++=0;//后置++,先进行解引用操作,在进行+1操作:先将指针指向的空间赋值为0,在将指针往后移动一位
       }
       return 0;
}

注意:允许指向数组的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较

*指针减指针

前提条件:两个指针要指向同一块空间

#define _CRT_SECURE_NO_WARNINGS 1
#define N_VALUES 5
#include
int main()
{
       int arr[10] = { 0 };
       printf("%d", &arr[9] - &arr[0]);
       return 0;
}

打印结果是9

指针-指针的绝对值得到的是两个指针之间的元素个数

用处?

写一个函数求一个字符串的长度

1.不写函数可以用strlen

2.写函数:

核心代码:

while if(*str!=0)

{

   count++;

   str++;

}return count;

3.递归

4.指针-指针

char start=str;

while if(*str!=0)

{

   str++;

}return str-start;

5.指针和数组

①指针和数组是不同的对象

指针和数组是不同的对象,指针是一种变量存放地址的,大小4/8个字节

数组是一组相同类型的集合,是可以放多个元素的,大小去结余元素个数和元素的类型

②数组的数组名是数组首个元素的地址,地址是可以放在指针变量中可以通过指针访问数组

#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
       int arr[10] = { 0 };
       int* p = arr;
       for (int i = 0; i < 10; i++)
       {
              *p = i + 1;
              p++;
       }
       p = arr;//这里为什么会有一个这个操作?因为如果没有这个操作 此时p指向的是数组最后一个元素的地址,现在让p重新指向第一个元素
       for (int i = 0; i < 10; i++)
       {
              printf("%d", *p);
              p++;
       }
       return 0;
}

6.二级指针

#define _CRT_SECURE_NO_WARNINGS 1
#define N_VALUES 5
#include
int main()
{
       int a = 10;
       int* pa = &a;
       int** ppa = &pa;
       printf("%d", **ppa);
       return 0;
}

7.指针数组

首先区分几个概念:

指针数组是数组还指针?--->是数组,存放指针的数组

字符数组--存放字符的数组:char arr[5]

#define _CRT_SECURE_NO_WARNINGS 1
#define N_VALUES 5
#include
int main()
{
       int a = 10, b = 20, c = 30, d = 40, e = 50;
       int* arr[5] = { &a,&b,&c,&d,&e };
       for (int i = 0; i < 5; i++)
       {
              printf("%d ", *(arr[i]));
       }
       return 0;
}

用一维数组,模拟二维数组

#define _CRT_SECURE_NO_WARNINGS 1
#define N_VALUES 5
#include
int main()
{
       //模拟3行4列的数组
       int a[]={ 1,2,3,4 };
       int b[] = { 2,3,4,5 };
       int c[] = { 3,4,5,6 };
       int* arr[3] = { a,b,c };
       for (int i = 0; i < 3; i++)
       {
              for (int j = 0; j < 4; j++)
              {
                      printf("%d ", arr[i][j]);//等价于*(a[i]+j)
               }
              printf("\n");
       }
       return 0;
}

你可能感兴趣的:(c语言)