学生时代所学的一些 C 语言知识点回顾(2)——指针

简介: 学生时代所学的一些 C 语言知识点回顾(2)——指针 一 前言 承接上一篇,对 C 语言中的指针进行了回顾总结。文中的例子均为本人纯手工输入,在 Linux 环境中全部编译实践过。由于平时工作中大部分时间都使用 Linux ,许多深入的 Linux 体系知识需要掌握 C 语言才能深入地理解,故此,对 C 语言进行了一次回顾。

@[toc]

学生时代所学的一些 C 语言知识点回顾(2)——指针

一 前言

承接上一篇,对 C 语言中的指针进行了回顾总结。文中的例子均为本人纯手工输入,在 Linux 环境中全部编译实践过。由于平时工作中大部分时间都使用 Linux ,许多深入的 Linux 体系知识需要掌握 C 语言才能深入地理解,故此,对 C 语言进行了一次回顾。工作多年以后,才发现:曾经所学的一切知识并非一无是处,而是那时的自己太粗浅,太急功近利。就像 C 语言,在目前的工作中仍能发挥重大作用,时常能起到事半功倍的效果。关于这些,在后期我的分享中将会完美呈现,敬请关注。

二 一些例子

# include<stdio.h>

int main(int argc,char *argv[]){
  int i = 10, j, *p, *q, *x = &i;
  p = &i;
  q = p;
  j = *&i;
  printf("p = %d\n",*p);
  printf("q = %d\n",*q);
  printf("x = %d\n",*x);
  printf("j = %d\n",j);
  scanf("%d",&i);
  printf("p = %d\n",*p);
  printf("q = %d\n",*q);
  printf("x = %d\n",*x);
  printf("j = %d\n",j);
  return 0;
}
/*
p = 10
q = 10
x = 10
j = 10
98
p = 98
q = 98
x = 98
j = 10
*/

这个例子种,指针变量 x 在声明的同时进行了初始化工作,这种操作是合法的。在声明之后再进行初始化则需要以类似于指针变量 p 的方式进行初始化,仍然使用 *p = &i 这种声明方式是无法通过编译的。

通过 *p 这种方式使用指针值叫做间接寻址。此处的 * 称之为间接寻址运算符。

多个指针变量指向同一变量时,该变量的值改变之后,指针变量的值也随之改变。

*&i 对变量 i 使用 & 运算符产生指向指针变量的指针,对指针使用 * 运算符则可以返回到原始变量。

# include<stdio.h>

int main(int argc,char *argv[]){
  int *p, *q, i = 989, j = 2019;
  p = &i;
  q = &j;
  q = p;
  printf("p = %d\n",*p);
  printf("p : %p\n",p);
  printf("j = %d\n",j);
  printf("q = %d\n",*q);
  printf("q : %p\n",q);
  return 0;
}
/*
p = 989
p : 0x7fff51751e5c
j = 2019
q = 989
q : 0x7fff51751e5c
*/

同类型的指针变量可以相互复制,复制之后指向同一变量。

# include<stdio.h>

int main(int argc,char *argv[]){
  int *p, *q, i = 989, j = 2019;
  p = &i;
  q = &j;
  *q = *p;
  printf("p = %d\n",*p);
  printf("p : %p\n",p);
  printf("j = %d\n",j);
  printf("q = %d\n",*q);
  printf("q : %p\n",q);
  return 0;
}
/*
p = 989
p : 0x7ffc00d359ac
j = 989
q = 989
q : 0x7ffc00d359a8
*/

这段代码看起来跟上一段十分相似,但是运行结果却截然不同。赋值语句 q = p 把指针变量 p 的值复制到 q 指向的对象中,也就是 j 中,但是 p 和 q 的地址是不一样的。

# include<stdio.h>

int main(int argc,char *argv[]){
  char i, *p;
  p = &i;
  scanf("%c",p);
  printf("p = %c\n",*p);
  printf("i = %c\n",i);
  return 0;
}
/*
e
p = e
i = e
*/

在这一段代码中,如果删除 “p = &i;” 这一句,那么这段代码是不能顺利通过编译的,函数 scanf() 中的 变量 p 就相当于 &i, scanf() 读入的字符并存储于 i 中。此时,scanf() 中不能再使用运算符 &。

# include<stdio.h>

int main(int argc,char *argv[]){
  int a, b;
  int *max(int *,int *);
  scanf("%d%d",&a,&b);
  printf("The max number is: %d\n",*max(&a,&b));
  return 0;
}

int *max(int *a, int *b){
  *a = *a + 5;
  if (*a > *b)
    return a;
  else
    return b;
}
/*
1 4
The max number is: 6
*/

指针变量作为形参进行传递、运算,并函数的返回值类型为指针。再继续看下一段代码:

# include<stdio.h>

int main(int argc,char *argv[]){
  int a, b;
  int max(int *,int *);
  scanf("%d%d",&a,&b);
  printf("The max number is: %d\n",max(&a,&b));
  return 0;
}

int max(int *a, int *b){
  *a = *a + 5;
  if (*a > *b)
    return *a;
  else
    return *b;
}
/*
1 4
The max number is: 6
*/

同样的输入,一样的输出结果,形式不一样,实际上实现原理也是一样的,都返回指针,可以类比来理解。

# include<stdio.h>

int main(int argc,char *argv[]){
  int x = 2019, y=2023;
  int *a = &x, *b = &y, c;
  c = (*a + *b) * 2 + 20;
  printf("Sum: %d\n",c);
  return 0;
}
// Sum: 8104

以上代码的第4行和第5行互换,将不能通过编译。C 语言严格遵循先声明后使用的原则,指针也不例外。间接寻址在表达式中是可以直接使用的。需要说明的是:“int *a = &x, *b = &y, c;”这一行中的 * 不是间接寻址运算符,其作用是告知编译器 a 和 b 是两个指向 int 类型变量的指针。 “c = (*a + *b) * 2 + 20;”这一行的前两个 * 是间接寻址运算符,第三个 * 是乘法运算符。

# include<stdio.h>

int main(int argc,char *argv[]){
  int p;
  int example(int *);
  scanf("%d",&p);
  printf("%d\n",example(&p));
  return 0;
}

int example(int *p){
  int a = 10086;
  printf("The original value is: %d\n",*p);
  p = &a;
  return *p;
}

# include<stdio.h>

int main(int argc,char *argv[]){
  int p;
  int example(int *);
  scanf("%d",&p);
  printf("%d\n",example(&p));
  return 0;
}

int example(int *p){
  printf("The original value is: %d\n",*p);
  *p = 10086;
  return *p;
}

# include<stdio.h>

int main(int argc,char *argv[]){
  int p;
  int example(const int *);
  scanf("%d",&p);
  printf("%d\n",example(&p));
  return 0;
}

int example(const int *p){
  int x = 10086;
  printf("The original value is: %d\n",*p);
  p = &x;
  return *p;
}
/*
98
The original value is: 98
10086
*/

以上三段代码编译执行后均能得到一致的结果,但是如下代码却不能通过编译:

# include<stdio.h>

int main(int argc,char *argv[]){
  int p;
  int example(const int *);
  scanf("%d",&p);
  printf("%d\n",example(&p));
  return 0;
}

int example(const int *p){
  printf("The original value is: %d\n",*p);
  *p = 10086;
  return *p;
}

这说明使用了 const 关键字之后,不能改变指针指向的整数,但是能改变指针自身。因为实参是按值进行传递的,所以通过指针指向其他地方的方法给 p 赋新值不会对函数外部产生任何影响。在声明时,关键字 const 是不能省略的。继续看下面的代码。

# include<stdio.h>

int main(int argc,char *argv[]){
  int p;
  int example(int * const);
  scanf("%d",&p);
  printf("%d\n",example(&p));
  return 0;
}

int example(int * const p){
  printf("The original value is: %d\n",*p);
  *p = 10086;
  // int x = 10086;
  // p = &x;
  return *p;
}
/*
98
The original value is: 98
10086
*/

本段代码中,如果取消注释部分,则不能通过编译。在此处,可以改变指针指向的整数,但是不能改变改变指针自身。进一步尝试:

# include<stdio.h>

int main(int argc,char *argv[]){
  int p;
  int example(const int * const);
  scanf("%d",&p);
  printf("%d\n",example(&p));
  return 0;
}

int example(const int * const p){
  printf("The original value is: %d\n",*p);
  // *p = 10086;
  // int x = 10086;
  // p = &x;
  return *p;
}
/*
98
The original value is: 98
98
*/

本段代码中出现了两个 const 关键字。代码中被注释的3行,取消任意一部分均不能通过编译。这种情况说明:通过这种声明之后,既不能改变指针指向的整数,也不能改变指针自身。不过这种情况比较少见。

三 小结

此部分主要回顾了指针,使用了较长篇幅验证了 const 关键字,可能还存在较多理解上的误区,希望各位多多指点、沟通交流,彼此进步。

相关文章
|
2月前
|
存储 NoSQL 编译器
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
指针是一个变量,它存储另一个变量的内存地址。换句话说,指针“指向”存储在内存中的某个数据。
124 3
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
|
2月前
|
存储 编译器 C语言
【C语言】指针大小知多少 ?一场探寻C语言深处的冒险 !
在C语言中,指针的大小(即指针变量占用的内存大小)是由计算机的体系结构(例如32位还是64位)和编译器决定的。
168 9
|
2月前
|
安全 程序员 C语言
【C语言】指针的爱恨纠葛:常量指针vs指向常量的指针
在C语言中,“常量指针”和“指向常量的指针”是两个重要的指针概念。它们在控制指针的行为和数据的可修改性方面发挥着关键作用。理解这两个概念有助于编写更安全、有效的代码。本文将深入探讨这两个概念,包括定义、语法、实际应用、复杂示例、最佳实践以及常见问题。
61 7
|
3月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
265 13
|
3月前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
3月前
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
213 3
|
3月前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
3月前
|
程序员 C语言
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门。本文深入探讨了指针的基本概念、声明方式、动态内存分配、函数参数传递、指针运算及与数组和函数的关系,强调了正确使用指针的重要性,并鼓励读者通过实践掌握这一关键技能。
71 1
|
3月前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
3月前
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。

热门文章

最新文章