C语言学习记录——7000+字长文-复习&学习指针(指针、地址、指针变量、指针与数组、指针与函数、指针数组、多级指针)一

简介: C语言学习记录——7000+字长文-复习&学习指针(指针、地址、指针变量、指针与数组、指针与函数、指针数组、多级指针)一

指针与地址

地址也称内存地址。

概念:

在计算机中,所有的运行数据都存放在内存储器中,内存储器的一个字节占用一个内存单元。为方便访问这些内存单元,我们为每个内存单元进行了编号,这些编号就称为内存地址。

我们简单理解为:内存储器为一个酒店,内存单元是住客们,内存地址就相当于他们所住房间的门牌号。

例如:使用取地址运算符&时,就是在获取变量的内存地址

指针

概念:

根据内存地址就可以找到相应的内存单元,所以通常也把地址称为指针。

看下面的代码:

#include <stdio.h>
int main()
{
  int n;
  int *p = &n;
  printf("%p\n", p);
  return 0;
}

其运行结果为:  0032F824

该结果即是变量n的内存地址,也称为其指针。

 

指针变量

概念:

在C语言中,允许用一个变量来存放指针,这种变量就称为指针变量。

其与一般变量一样,要先声明后使用

定义形式:

类型说明符(数据类型) * 指针变量名;

其中类型说明符表示该指针变量所指向的变量是什么数据类型,* 是指说明符,当*单独使用时,则为解引用操作符。

例如:

#include <stdio.h>
int main()
{
  int n = 5;
  int *p = &n;
  printf("%d\n", *p); //此处对P进行解引用操作,通过p的地址找到变量n
  return 0;
}

运行结果为:   5

需要注意一点的是:* 是单目运算符,结合性为“左结合”,后面只能接指针变量。

 

指针与数组

指针与一维数组

指向一维数组元素的指针

如果定义了一个一维数组,此时再定义一个指针,并把数组的第一个元素的起始地址赋值给该指针,则该指针就指向了这个一维数组。

例如:

#include <stdio.h>
int main()
{
  int arr[5] = { 1,2,3,4,5 },i;
  int *p;
  p = &arr[0];
  for (i = 0; i < 5; i++)
  {
    printf("arr[%d] = %d\n", i, *(p + i));
  
  }
  return 0;
}

其运行结果为:

指针p与一维数组arr的关系

image.png

指针与整数的加减运算

当指针指向数组元素后,加上或减去一个整数n,表示把指针的当前位置(指向某数组元素)向后或向前移动n个元素的位置。

例如:

#include <stdio.h>
int main()
{
  int arr1[5] = { 1,2,3,4,5 };
  float arr2[5] = { 1.0,2.0,3.0,4.0,5.0 };
  int *p;
  float *b;
  p = &arr1[0];
  b = &arr2[0];
  printf("指针加整数前\n%d\n%.2f\n", *p, *b);
  printf("\n");
  p += 3;
  b += 4;
  printf("指针加整数后\n%d\n%.2f\n", *p, *b);
  return 0;
}

其运行结果为:

 

指针的增量运算

指向数组元素的指针变量的值可以改变。如p++是合法的,使得p指向下一个数组元素。而arr++是非法的,因为arr是数组的首地址,是一个常量。

例如:

#include <stdio.h>
int main()
{
  int arr[5] = { 1,2,3,4,5 },*p;
  p = &arr[0];
  printf("增量运算前\n%d\n", *p);
  p++; //或者++p; 
  //此时指针在原来的基础上加上了4(查阅资料,根据VC++6.0编译环境int型数据占4个字节)
  //从而使得指针指向数组的下一个元素
  printf("\n");
  printf("增量运算后\n%d\n", *p);
  return 0;
}

其运行结果为:

 

指针与指针的减法运算

当两个指针指向同一片连续的存储单元时,指针的减法运算的结果是一个整数,其值为这两个指针变量中的地址之差除以数据类型的长度。

例如:

#include <stdio.h>
int main()
{
  //建立一维数组和两个指针变量
  float arr[5] = { 1.0,5.0,2.0,6.0,9.0 },*p,*b;
  p = &arr[4];
  b = &arr[1];
 
  //计算float型数据占多少个字节
  printf("float型数据占%d个字节\n\n", sizeof(arr[0]));
 
  //打印出p和b的地址,不难算出(16进制转10进制来计算)相减之后结果为12
  printf("p中存放的地址:%p\nb中存放的地址:%p\n两个地址相减得到结果为12\n\n", p, b);
 
  //打印出两个指针相减的结果
  printf("两个指针相减的结果为:%d\n(12 / 4)", p - b);
  return 0;
}

其运行结果为:

 

指针与指针的关系运算

当两个指针指向同一片连续的存储单元时,两个指针可以进行关系运算,即表示它们之间的位置关系。

int arr[10],*p,*b;
 
p == b;  //表示判断p和b是否指向同一数组元素
 
p > b;   //表示判断p所指元素是否在b所指元素的后面
 
p < b;   //表示判断p所指元素是否在b所指元素的前面

用这一知识点,将数组arr中n个整数按相反的顺序存放

#include <stdio.h>
#define N 5
int main()
{
  int arr[N], i, tmp, * p, * q;
  printf("请随机输入%d个数字\n", N);
  for (i = 0; i < N; i++)
  {
    printf("第%d个:", i + 1);
    scanf("%d", &arr[i]);
  }
  p = arr;               //p指向数组中的第一个元素
  q = arr + (N - 1);     //q指向数组中的最后一个元素
  while (p < q)          //逆序存放数组中的元素
  {
    tmp = *p;
    *p = *q;
    *q = tmp;
    p++;
    q--;
  }
  printf("逆序输出为:");
  for (i = 0; i < N; i++)
    printf("%d ", arr[i]);
  printf("\n");
  return 0;
}


其运行结果为:

 

指针与二维数组

二维数组的元素及地址

定义一个二维数组int arr[ 3 ][ 4 ];表示二维数组有3行4列共12个元素,在内存中按行存放。

二维数组arr也可以理解为由3个元素组成,即arr[ 0 ]、arr[ 1 ]、arr[ 2 ],而每个元素是一个一维数组,且都包含了4个元素。

二维数组在内存中的存储方式示意图 image.png

通过行指针引用二维数组的元素

行指针

行指针是一种特殊的指针,它专门用于指向一维数组,定义行指针的一般形式如下:

类型说明符(* 指针名) [常量表达式];

其中,类型说明符代表行指针所指一维数组的元素类型,指针名与前面的指针说明*必须用括号括起来,常量表达式是指针所指向的一维数组的长度。

例如:

int arr[3][4];
int (*p)[4] = &arr[0];
//也可以写成int (*p)[4] = arr;

上面语句中定义了一个指向一维数组的指针p,指向包含4个int型元素的一维数组arr[ 0 ]。此时p + 1指向下一个一维数组arr[ 1 ],因此,*(p + 1)+ 2是arr[ 1 ][ 2 ]的地址,那么


*(*(p + 1)+ 2)就是二维数组元素arr[ 1 ][ 2 ]的值

故,以下几种方式都可以表示二维数组元素arr[ i ][ j ].

int arr[3][4], i , j ;
int (*p)[4] = &arr[0];
//二维数组arr,arr首元素的地址p
 
* (*(arr + i) + j);
 
* (*(p + i) + j);
 
p[i][j];

通过列指针引用二维数组的元素

当指针p指向二维数组的首元素之后,p + 1将指向二维数组的第二个元素,p + 2将指向二维数组的第三个元素,以此类推

例如:

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

其运行结果为:

 

用指针法输入输出二维数组中的各个元素:

 

//行指针法
#include <stdio.h>
int main()
{
  int arr[3][4], i, j;
  int (*ptr) [4] = &arr[0];
  for (i = 0; i < 3; i++)
  {
    for (j = 0; j < 4; j++)
    {
      scanf("%d", *(ptr + i) + j);
    }
  }
  printf("\n");
  for (i = 0; i < 3; i++)
  {
    for (j = 0; j < 4; j++)
    {
      printf("%d\t", *(*(ptr + i) + j));
    }
    printf("\n");
  }
  return 0;
}
//列指针法
#include <stdio.h>
int main()
{
  int arr[3][4],i,j;
  int *p = &arr[0][0];
  for (i = 0; i < 3; i++)
  {
    for (j = 0; j < 4; j++)
    {
      scanf("%d", p+i+j);
    }
  }
  printf("\n");
  for (i = 0; i < 3; i++)
  {
    for (j = 0; j < 4; j++)
    {
      printf("%d\t", *(p + i + j));
    }
    printf("\n");
  }
  return 0;
}

以上运行结果都为:

 

指针与字符数组

字符数组在C语言中可以用字符串常量初始化,也可以整串地输入或输出。

由于指针与数组的等价性,字符指针也有如下特点:


C语言学习记录——7000+字长文-复习&学习指针(指针、地址、指针变量、指针与数组、指针与函数、指针数组、多级指针)二:https://developer.aliyun.com/article/1530355

目录
相关文章
|
8月前
|
存储 C语言
`scanf`是C语言中用于按格式读取标准输入的函数
`scanf`是C语言中用于按格式读取标准输入的函数,通过格式字符串解析输入并存入指定变量。需注意输入格式严格匹配,并建议检查返回值以确保读取成功,提升程序健壮性。
1468 0
|
10月前
|
安全 C语言
C语言中的字符、字符串及内存操作函数详细讲解
通过这些函数的正确使用,可以有效管理字符串和内存操作,它们是C语言编程中不可或缺的工具。
452 15
|
人工智能 Java 程序员
一文彻底搞清楚C语言的函数
本文介绍C语言函数:函数是程序模块化的工具,由函数头和函数体组成,涵盖定义、调用、参数传递及声明等内容。值传递确保实参不受影响,函数声明增强代码可读性。君志所向,一往无前!
616 1
一文彻底搞清楚C语言的函数
|
存储 编译器 C语言
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
683 3
|
存储 人工智能 Java
一文轻松拿捏C语言的指针的基础使用
本文介绍了C语言中的指针概念,包括直接访问和间接访问内存的方式、指针变量的定义与使用、取址运算符`&`和取值运算符`*`的应用,帮助读者深入理解指针这一C语言的核心概念。君志所向,一往无前!
340 0
指针进阶(C语言终)
指针进阶(C语言终)
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
1866 13
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
846 4
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
260 0
|
编译器 C语言
【C语言初阶】指针篇—下
【C语言初阶】指针篇—下