C 中的指针:C 编程中的指针是什么?类型

⚡ 智能摘要

C 语言中的指针是存储另一个变量内存地址的变量。它们支持动态内存分配、高效的数组和字符串处理以及复杂的数据结构,并可通过取地址和解引用运算符来读取或修改值。

  • 📌 定义: 指针保存着另一个变量的内存地址。
  • 🔧 Opera目的: & 运算符返回一个地址;* 运算符解引用该地址。
  • 🧷 宣言: 写入数据类型为 *name 的数据,然后用变量的地址进行初始化。
  • 🏷️ 类型: 空指针、void 指针和无意义指针的行为各不相同,需要特别注意。
  • 算术: 将指针加一,指针就会移动其基本类型的大小。
  • 🤖 人工智能协助: AI 工具在审查过程中调试段错误并标记悬空指针。

C语言中的指针

C语言中的指针是什么?

A 指针 在C语言中,指针是一种存储另一个变量地址的变量。指针还可以指向另一个指针或函数。指针可以递增或递减,以指向下一个或上一个内存地址。指针的目的是节省内存空间并提高执行速度。

如何在 C 中使用指针

如果我们声明一个 int 类型的变量 v,v 会存储一个值。每个变量除了值之外,还有一个地址,即它在内存中的位置。可以通过在变量名前加上 & 符号来获取地址。如果打印变量的地址,它看起来像一个随机数,每次运行结果都可能不同。

指针并不存储值,而是存储变量的地址。例如:

int *y = &v;
变量 指针
A 折扣值 存储在一个 命名 存储/内存地址。 A 变量 存储/内存地址 另一个 变量。

声明指针

和变量一样,指针 C程序设计 指针必须先声明才能使用。指针声明的形式如下:

data_type *pointer_variable_name;

在这里, 数据类型 `type` 是指针的基类型,指示指针指向的变量的类型。星号 (*),与乘法符号相同,是间接运算符,用于声明指针。一些有效的指针声明如下:

int    *ptr_thing;       /* pointer to an integer */
int    *ptr1, thing;     /* ptr1 points to an int; thing is an int */
double *ptr2;           /* pointer to a double */
float  *ptr3;           /* pointer to a float */
char   *ch1;            /* pointer to a character */

初始化指针

声明指针后,我们需要用变量地址对其进行初始化。如果指针未初始化就被使用,结果可能难以预料,甚至造成灾难性后果。要获取变量的地址,请在变量名前使用 & 符号:

pointer = &variable;

下面给出一个简单的程序来演示指针:

#include <stdio.h>
int main()
{
   int a = 10;     // variable declaration
   int *p;         // pointer variable declaration
   p = &a;        // store address of a in pointer p
   printf("Address stored in p is: %x\n", p);  // access the address
   printf("Value stored in p is: %d\n", *p);    // access the value
   return 0;
}

输出:

Address stored in p is: 60ff08
Value stored in p is: 10
Opera器
* 它有两个用途:声明一个指针,并返回被引用变量的值(解引用)。
& 其用途只有一个:返回变量的地址。

C 语言中的指针类型

空指针

我们在声明时将值赋为 NULL 来创建一个空指针。当指针尚未被赋予任何地址时,这非常有用。空指针始终包含值 0。

#include <stdio.h>
int main()
{
   int *p = NULL;     // null pointer
   printf("The value inside variable p is: %x", p);
   return 0;
}

空指针

void 指针,也称为通用指针,没有任何标准数据类型。它使用关键字 void 创建,可以存储任何变量的地址:

#include <stdio.h>
int main()
{
   void *p = NULL;    // void pointer
   printf("The size of pointer is: %d\n", sizeof(p));
   return 0;
}

野生指示犬

如果一个指针没有被初始化,就称它为野指针。这些指针效率很低,因为它们可能指向未知的内存位置,这会导致问题甚至程序崩溃。务必谨慎使用野指针:

#include <stdio.h>
int main()
{
   int *p;          // wild pointer
   printf("%d", *p);
   return 0;
}

C 语言中其他类型的指针包括悬空指针、复杂指针、近指针、远指针和巨型指针。

直接和间接访问指针

在 C 语言中,有两种等效的方式来访问和操作变量的内容。直接访问直接使用变量名,而间接访问使用指向变量的指针:

#include <stdio.h>
int var = 1;        /* declare and initialize an int variable */
int *ptr;           /* declare a pointer to int */
int main(void)
{
   ptr = &var;       /* point ptr to var */
   printf("\nDirect access, var = %d", var);
   printf("\nIndirect access, var = %d", *ptr);
   *ptr = 48;        /* change var through the pointer */
   printf("\nIndirect access, var = %d", *ptr);
   return 0;
}

C 中的指针算术

使用指针时,请遵守以下优先级规则。运算符 * 和 & 与一元运算符(取反 !、加 ++、减 -)的优先级相同。在同一个表达式中,一元运算符 *、&、!、++ 和 — 的计算顺序是从右到左。如果指针 P 指向变量 X,则在任何可以写出 X 的地方都可以使用 *P。以下表达式是等价的:

口语 等效表达
Y = *P + 1 Y = X + 1
*P = *P + 10 X = X + 10
*P += 2 X += 2
++*P ++十
(*P)++ X++

最后一种情况需要使用括号:因为一元运算符 * 和 ++ 是从右到左计算的,如果没有括号,指针 P 会被递增,而不是它指向的对象。指针可执行的算术运算包括赋值、递增、递减以及加减运算。trac表示一个整数偏移量,它将指针移动该偏移量对应的元素个数(每一步等于基本类型的字节大小)。

C语言指针和数组示例

传统上,我们使用索引来访问数组元素,但指针也让这一切变得简单。指向数组名的指针会指向第一个元素:

#include <stdio.h>
int main()
{
   int a[5] = {1, 2, 3, 4, 5};   // array initialization
   int *p;                       // pointer declaration
   p = a;                       // p points to the first element; same as &a[0]
   for (int i = 0; i < 5; i++)
   {
      printf("%d\n", *p);            // print element
      p++;                      // move to the next element
   }
   return 0;
}

将一个数字加到指针上,指针就会向前移动相应的元素个数。如果 p 指向内存地址 0,那么 p + 1 会使指针指向内存地址 1。

C 指针和字符串示例

字符串是一个以空字符'\0'结尾的字符对象数组。我们可以使用指针来操作字符串:

#include <stdio.h>
#include <string.h>
int main()
{
   char str[] = "Hello Guru99!";
   char *p;
   p = str;
   printf("First character is: %c\n", *p);
   p = p + 1;
   printf("Next character is: %c\n", *p);
   p = str;                     // reset the pointer
   for (int i = 0; i < strlen(str); i++)
   {
      printf("%c\n", *p);
      p++;
   }
   return 0;
}

处理字符串的另一种方法是使用指针数组:

#include <stdio.h>
int main()
{
   char *materials[] = {"iron", "copper", "gold"};
   for (int i = 0; i < 3; i++)
      printf("%s\n", materials[i]);
   return 0;
}

C 语言中指针的优点

  • 指针可用于直接访问内存位置。
  • 它们提供了一种访问数组元素的有效方法。
  • 它们用于动态内存分配和释放。
  • 它们用于构建复杂的数据结构,例如链表、图和树。

C 语言中指针的缺点

  • 指针理解起来有点复杂。
  • 它们可能导致诸如段错误或访问非预期内存位置之类的错误。
  • 给指针赋错误值可能会导致内存损坏。
  • 如果内存没有被释放,指针也会导致内存泄漏。
  • 程序员有责任谨慎处理指针。

常见问题

悬空指针指向已被释放或超出作用域的内存。避免这种情况的方法是:在调用 free 函数后立即将指针设置为 NULL,并在使用前检查指针是否为 NULL。

对空指针进行解引用会导致段错误,并使程序在运行时崩溃。在使用 * 运算符进行读写操作之前,务必检查指针是否为空。

双指针(声明为 int **pp)存储另一个指针的地址。它用于动态二维数组以及在函数内部修改指针参数。

指针存储内存地址,在给定的平台上,地址的宽度相同,通常 32 位平台为 4 字节,64 位平台为 8 字节,无论它指向什么类型。

函数指针存储函数的地址,以便可以动态调用它。它广泛用于回调函数和构建运行时选择的函数表。

malloc 和 calloc 等函数返回一个指向运行时在堆上分配的内存的指针。您可以通过该指针访问该内存,并使用 free 函数释放它以避免内存泄漏。

是的。人工智能助手会读取段错误及其周围的代码,然后解释可能的原因,例如未初始化或已释放的指针,并提出修复建议供您审核。

人工智能驱动的分析器,以及 Valgrind 等工具,可以标记出从未释放的内存和释放后仍在使用的指针。它们能够自动审查代码,并在代码发布前突出显示风险模式。

总结一下这篇文章: