C语言:初阶指针

简介: C语言:初阶指针

内存和地址

在计算机中,一切的运算数据都会暂存在内存中,当我们需要调用内存中某个部分的时候,就会用到指针。我们可以把计算机的内存比作一条街上的一排房屋,每个房屋都会容纳一定的数据,并可以用房号来标识;首先这个比喻是有一定的局限性的,不过对于初学者来理解,是足够的;这里就不必展开了;那这个房屋得多大呢?在计算机中内存中由数亿上计的位(bit)组成,所以,房屋储存以字节为单位;


假设把上面一个格子当作一个字节,那么每个格子就可存8个位;内存中每个位置都包含一些值;每个字节的位置用地址来标识;在这里,地址是十六进制的;为了存储更大的值,我们把两个或更多个字节合在一起作为一个更大的内存单位。我们的系统中,地址按字节编址,short类型占用2字节,double类型占用8字节;在这里,内存中的每个位置都是由独一无二的地址标识的;当我们要引用某个数据时,就要调用到某个内存,我们通过地址来找到该位置,而指针,就是来记住这个地址的;


指针

所以,指针是内存中一个最小单元的编号,也就是地址,口语中说的指针通常指的是指针变量。

如:

#include <stdio.h>
int main()
{
 int a = 10;
 int *p = &a;
  //a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量中,p就是一个之指针变量。
 return 0;
}


对于变量a来说,会在内存中开辟一块空间,对于变量a,我们要取到它的地址,可以用到&操作符。

一般来说,在32位机器上,一个指针变量大小为4个字节,64位机器上,8个字节。

值与类型

先看下面代码:

#include <stdio.h>
int main()
{
 int a=112,b=1;
 float c=3.14;
 int* d=&a;
 int* e=&c;
 return 0;
}


变量表示:

我们知道a是整型存储类型的,对于a取地址,对他解引用是它本身,但是,c是浮点型类型的,对他取地址后解引用,却是一个整数;答案是该变量包含了一系列0或1的位,对于它是整型类型或者是浮点型类型,取决于它的算术指令;所以,不能简单的通过检查一个值的位来判断它的类型;


接着看以下代码:

char  *pc = NULL;
int   *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL


指针定义类型为 type+*;

对于不同类型的指针,是为了存储相应类型的地址;如char类型指针存储char变量的地址。那不同类型的指针又有什么不同呢?

#include <stdio.h>
int main()
{
 int n = 10;
 char *pc = (char*)&n;//括号是强制转换
 int *pi = &n;
 printf("%p\n", &n);
 printf("%p\n", pc);
 printf("%p\n", pc+1);
 printf("%p\n", pi);
 printf("%p\n", pi+1);
 return  0;
}


结果:

我们可以看到,对于char类型和int类型取地址,是位于n内存上的地址,

地址加1后,

总结:指针的类型决定了指针向前或者向后走一步有多大(距离)

最后:

//演示实例
#include <stdio.h>
int main()
{
 int n = 0x11223344;//表示地址位置
 char *pc = (char *)&n;
 int *pi = &n;
 *pc = 0;  
 *pi = 0; 
 return 0;
}


一开始的地址:


0x11223344


pc解引用后:


0x11223300


pi解引用后:


0x00000000


在这里,电脑采用了小端的存储方式。在电脑中,数据一定是从内存的低地址依次向高地址读取和写入,小端存储,会将低位存储到低地址处,高地址存储到高地址处,也即存储时是0x44332211.所以,pc解引用后,由于它是char类型的,大小只有一个字节,所以只对一个字节内存大小赋值为0,即为44;而pi为int类型,大小4个字节,所以当它解引用后,就会使整个地址为0。


总结:

指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。


指针运算

指针±整数

#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指针+-整数;指针的关系运算
int main()
{
    for (vp = &values[0]; vp < &values[N_VALUES];)
{
     *vp++ = 0;
}
 }


在这里,values表示一个数组,vp是一个浮点型指针,在for循环中,vp赋值为value首元素地址,每当它+1后,地址就会不断先后移动4个字节,直至与values[5]地址相同,循环停止;

指针-指针

int my_strlen(char *s)
{
       char *p = s;
       while(*p != '\0' )
              p++;
       return p-s;
}


这是一个求字符串长度的函数,假设有一个字符串为“abcdef" ,指针位于初始位置a地址上,p指针表示初始位置地址,当循环之后,p走到了’\0’的位置,最后相减返回,即为字符串长度6。

当然,这里给出结论:指针-指针是返回的是之间有多少个元素,也即地址差/整型字节。一般可以运用到字符串和数组中。上面例子由于是char类型,看不出来。下面给出一个例子:

#include<stdio.h>
int main()
{
    int arr[10];
    printf("%d",&arr[10]-&arr[0]);
    return 0;
}


结果:10

当然指针-指针的前提条件是指向同一块空间。

指针与数组

先看例子

#include <stdio.h>
int main()
{
 int arr[10] = {1,2,3,4,5,6,7,8,9,0};
    printf("%p\n", arr);
    printf("%p\n", &arr[0]);
    return 0;
}

可以看出arr地址即为首元素地址,当然两种情况除外。(数组章节有说明哦).

既然arr可以当作指针,那么就有以下的操作:

#include <stdio.h>
int main()
{
    int arr[] = {1,2,3,4,5,6,7,8,9,0};
    int *p = arr; //指针存放数组首元素的地址
    int sz = sizeof(arr)/sizeof(arr[0]);
    for(i=0; i<sz; i++)
   {
        printf("&arr[%d] = %p   <====> p+%d = %p\n", i, &arr[i], i, p+i);
   }
    return 0;
}


可以看到, p+i 其实计算的是数组 arr 下标为i的地址,那么我们可以通过指针来访问数组元素。

int main()
{
 int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
 int *p = arr; //指针存放数组首元素的地址
 int sz = sizeof(arr) / sizeof(arr[0]);
 int i = 0;
 for (i = 0; i<sz; i++)
 {
 printf("%d ", *(p + i));
 }
 return 0;
}


二级指针

指针变量也是变量,是变量就有地址。如int *p是一个指针变量,那么它的地址就由二级指针来存储


可以看到,a是整型变量,p是一级指针,解引用后为10,pp是二级指针,*pp表示一级指针的地址,**pp表示解一级指针的指向的内容。

野指针

野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)指针变量在定义时如果未初始化,其值是随机的,指针变量的值是别的变量的地址,意味着指针指向了一个地址是不确定的变量,此时去解引用就是去访问了一个不确定的地址,所以结果是不可知的。

所以,我们要规避野指针的情况。

1.创建指针记得初始化,当不知道指向哪里时,直接指向NULL,不能不管它;

2.不能使访问位置越界,如一个数组有10个元素,你访问到下标为10的位置,超过数组长度范围,这就是访问越界。

3. 指针指向空间释放,及时置NULL;

4. 避免返回局部变量的地址,局部变量的指针指向的地址会在函数走完后销毁,当返回到主函数时,主函数指针接收不到任何地址。

5. 指针使用之前检查有效性。

相关文章
|
5天前
|
安全 C语言
【C语言】如何规避野指针
【C语言】如何规避野指针
22 0
|
5天前
|
C语言
c语言指针总结
c语言指针总结
15 1
|
4天前
|
存储 安全 编译器
C语言详解指针(指针海洋的探索,将传值与传址刻在心里)
C语言详解指针(指针海洋的探索,将传值与传址刻在心里)
9 0
|
5天前
|
C语言
C语言(指针详解)重点笔记:指针易错点,都是精华
C语言(指针详解)重点笔记:指针易错点,都是精华
13 0
|
5天前
|
存储 C语言
C语言指针讲解(适用于初学者)
C语言指针讲解(适用于初学者)
6 0
|
5天前
|
存储 程序员 C语言
【C 言专栏】C 语言指针的深度解析
【4月更文挑战第30天】C 语言中的指针是程序设计的关键,它如同一把钥匙,提供直接内存操作的途径。指针是存储其他变量地址的变量,通过声明如`int *ptr`来使用。它们在动态内存分配、函数参数传递及数组操作中发挥重要作用。然而,误用指针可能导致错误,如空指针引用和内存泄漏。理解指针的运算、与数组和函数的关系,以及在结构体中的应用,是成为熟练 C 语言程序员的必经之路。虽然挑战重重,但掌握指针将增强编程效率和灵活性。不断实践和学习,我们将驾驭指针,探索更广阔的编程世界。
|
5天前
|
算法 搜索推荐 程序员
C语言中的函数指针和回调函数
C语言中的函数指针和回调函数
12 2
|
5天前
|
存储 编译器 C语言
【C语言】初步解决指针疑惑
【C语言】初步解决指针疑惑
8 0
|
5天前
|
C语言
C语言:数组和指针笔试题解析(包括一些容易混淆的指针题目)
C语言:数组和指针笔试题解析(包括一些容易混淆的指针题目)
|
5天前
|
存储 程序员 编译器
爱上C语言:指针很难?来来来,看看这篇(基础篇)
爱上C语言:指针很难?来来来,看看这篇(基础篇)

热门文章

最新文章