写在前面:学习的第一门语言是Java,之前对C也了解一点,也只是了解一点,在加上长时间没有接触了,基本就只会一个Hello World了。现在由于准备升本考试,不得不从头开始学C。这里从零开始,记录C语言学习点滴。欢迎正在学习C语言的小伙伴一起学习,未来可期,一起加油!

指针是C语言中一个非常重要的概念,也是C语言的特色之一。使用指针可以对复杂数据进行处理,能对计算机的内存分配进行控制,在函数调用中使用指针还可以返回多个值。

地址和指针

地址和指针是计算机中的两个重要概念,在程序运行过程中,变量或者程序代码被存储在以字节为单位组织的存储器中。在C语言中,如果定义了一个变量,在编译时就会根据该变量的类型给它分配相应大小的内存单元。例如:假设int类型变量占 2 个字节,则需要分配 2 个字节的内存单元。

计算机为了对内存单元中的数据进行操作,一般是按“地址”存取的,也就是说对内存单元进行标识编号。假设如下有变量定义:

int x = 18, y = 24, z = 20;

因为int类型变量的存储长度为两个字节,因此假设C编译器将他们分配到地址为1000 ~ 1001、1002 ~ 1003和1004 ~ 1005的内存单元中。如下图:
在这里插入图片描述
实际上就在程序中,通过变量名进行操作,如调用函数printf("%d", x),输出X的值20。而程序执行时是将变量翻译为它所在的内存地址进行操作的,上述输出操作可以描述为:将X所在的内存地址1000 ~ 1001单元的内容按照整形格式输出。一般以变量所在的内存单元的第一个字节的地址作为它的地址,如变量X的内存地址是1000,y的内存地址是1002,z的地址是1004。变量X、y、z的内容分别为20、24、20。
要注意区分内存单元的内容和内存单元的地址。

在C程序中还有一种使用变量的方法,即通过变量的地址进行操作:用指针访问内存和操纵地址。
假设在定义一个变量P,它位于2000单元,该单元中存放了变量X的地址1000,如下图:
在这里插入图片描述
此时,取出变量P的值1000,就可以访问内存1000单元,实现对变量X的操作,也就是说通过变量P,可以间接访问变量X。
与直接使用变量X相比较,使用变量P访问变量X的过程实现了对变量X的间接操作。这种专门用来存放变量地址的变量称为“指针变量”,简称指针。
指针是用来存放内存地址的变量,如果一个指针变量的值是另一个变量的地址,给指针变量指向那个变量。上面提到的P就是一个指针变量,它存放了变量X的地址,即指针变量P指向变量X。
前面几篇多次看到把地址作为scanf()的输入参数的用法。例如,函数调用scanf("%d", &n),把输入的值存储到变量n所在的内存单元里。其中&n表示变量n的内存地址或存储位置。这里&称为地址运算符,&是一元运算符,与其他一元运算符有同样的优先级。

指针变量的定义

如果在程序中声明一个变量并使用地址作为该变量的值,那么这个变量就是指针变量。定义指针变量的一般形式为:
*类型名 指针变量名;
类型名指定指针变量所指向变量的类型,必须是有效的数据类型,如:int,float,char等。指针变量名是指针变量的名称,必须是一个合法的标识符。

int i, *p;

声明变量 i 是int型,变量 p 是指向int型变量的指针。指针值可以是特殊的地址0,也可以是一个代表机器地址的正整数。
指针声明符 * 在定义指针变量时被使用,说明被定义的那个变量是指针。

指针变量用于存放变量的地址,由于不同类型的变量在内存中占用不同大小的存储单元,所以只知道内存地址,不能确定该地址上的对象。因此在定义指针变量时,除了指针变量名,还需要说明该说明指针变量所指向的内存空间上所存放数据的类型。如下:

int *p;     /* 定义一个指针变量P,指向整形变量 */
char *cp;		/* 定义一个指针变量cp,指向字符型变量 */
float * fp; 		/* 定义一个指针变量fp,指向实型变量 */
double *dp1, *dp2;		/* 定义两个指针变量dp1和dp2,指向双精度实型变量 */

定义多个指针变量时,每个指针变量前面都必须加上*
指针变量的类型不是指指针变量本身的类型,而是指定它所指向的变量的数据类型。

定义指针及指针赋值

int i, *p;
p = &i;
p = 0;
p = NULL;
p = (int *) 100;

p = &i;语句中的指针p被看作是指向变量 i 或存放变量 i 的地址,也就是将指针p和变量 i 关联起来,这也是指针最常用的赋值方法。指针变量p和整型变量 i 之间的关系如下:
在这里插入图片描述
p = 0;和p = NULL;语句说明了怎样把特殊值0赋值给指针p,这时指针的值为NULL。常量NULL在系统文件stdio.h中被定义,其值为0,将他赋给指针时代表空指针。
p = (int *) 100;使用强制类型转换(int *)来避免编译错误,表示P指向地址为100的int类型变量。不建议这样使用,一般不将绝对地址赋值给指针,NULL例外。

在定义指针变量时,要注意以下几点。

  1. 指针变量名是一个标识符,要按照C标识符的命名规则对指针变量进行命名。
  2. 指针变量的数据类型是它所指向的变量的类型,一般情况下一旦指针变量的类型被确定后,他只能指向同种类型的变量。
  3. 在定义指针变量时需要使用指针声明符 * ,但指针声明符并不是指针的组成部分。例如:定义int *p;说明p是指针变量,而不是*p;

指针的基本运算

如果指针的值是某个变量的地址,通过指针就能间接访问那个变量,这些操作由取地址运算符&和间接访问运算符 * 完成。此外,相同类型的指针还能进行赋值、比较和算术运算。

1、取地址运算和间接访问运算
单目运算符 & 用于给出变量的地址。例如:

int *p, a = 3;
p = &a;

将整型变量a的地址赋给整型指针p,使指针p指向变量a。也就是说,用运算符&取变量a的地址,并将这个地址值作为指针p的值,使指针p指向变量a。

指针的类型和它所指向变量的类型必须相同。

在程序中,“ * ” 除了被用于定义指针变量外,还被用于访问指针所指向的变量,它也称为间接访问运算符。例如:但p指向a时,*p和a访问同一个存储单元,*p的值就是a的值,如下图:
在这里插入图片描述
取地址运算和间接访问运算示例。

#include<stdio.h>

int main(){
    int a = 3, *p;  /* 定义整型变量a和整型指针p */
    p = &a;     /* 把变量a的地址赋给指针p,即p指向a */
    printf("a = %d, *p = %d\n", a, *p);     /* 输出变量a的值和指针p说指向变量的值 */

    *p = 10;    /* 对指针p所指向的变量赋值,相当于对变量a赋值 */
    printf("a = %d, *p = %d\n", a, *p);

    printf("请输入a的值:");
    scanf("%d", &a);    /* 输入a */

    printf("a = %d, *p = %d\n", a, *p);
    (*p)++;     /* 将指针所指向的变量加1 */
    printf("a = %d, *p = %d\n", a, *p);

    return 0;
}

运行结果:
在这里插入图片描述
表达式*p = *p + 1、++p和(p)++,都是将指针p所指向变量的值加1。而表达式p++等价于*(p++),先取p的值作为表达式的值,在将指针p的值加1,运算后,p不再指向变量a。如:

int a = 1, x, *p;
p = &a;
x = *p++;

指针p先指向a,其后的语句x = *p++;将p所指向的变量a的值赋给变量x,然后修改指针的值,使得指针p不再指向变量a。

2、赋值运算
一旦指针被定义并赋值后,就可以如同其他类型变量一样进行赋值运算。例如:

int a = 3, *p1, *p2;	/* 定义整型变量指针p1和p2 */
p1 = &a;		/* 使指针p1指向整型变量a */
p2 = p1;

将变量a的地址赋给指针p1,再将p1的值赋给指针p2,因此指针p1和p2都指向变量a。此时,*p1、*p2和a访问同一个存储单元,它们的值一样。如下:
在这里插入图片描述

只能将一个指针的值赋给另一个相同类型的指针。

指针变量的初始化

指针变量在定义后需要先赋值再引用。在定义指针变量时,可以同时对它赋初值。例如:

int a;
int *p1 = &a;	/* 在定义指针p1的同时给其赋值,使指针p1指向变量a */
int *p2 = p1;     /* 在定义指针p2的同时对其赋值,使p2和p1的值相同,都指向变量a */

在进行指针初始化的时候需要注意一下几点。

  1. 在指针变量定义或者初始化时变量名前面的“ * ”只表示该变量是个指针变量,它既不是乘法运算又不是间接访问符。
  2. 把一个变量的地址作为初始化值赋给指针变量时,该变量必须在此之间已经定义。因为变量只有在定义后才被分配存储单元,它的地址才能赋给指针变量。
  3. 可以用初始化了的指针变量给另一个指针变量作初始化值。
  4. 不能用数值作为指针变量的初值,但可以将一个指针帮你初始化为一个空指针。例如:int *p = 1000; 是不对的,而int *p = 0; 是将指针变量初始化为空指针。这里0是ASCII字符NULL的值。
  5. 指针变量定义时的数据类型和它说指向的目标变量的数据类型必须一致,因为不同的数据类型所占用的存储单元的字节数不同。

由于初学C语言,上述内容如有错误地方,恳请各位大佬指出!

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐