C 中的三重指针:这是风格问题吗?

2024-04-09

我觉得 C 中的三重指针被视为“坏”。对我来说,有时使用它们是有意义的。

从基础开始,单指针有两个目的:创建数组,并允许函数更改其内容(通过引用传递):

char *a;
a = malloc...

or

void foo (char *c); //means I'm going to modify the parameter in foo.
{ *c = 'f'; }

char a;
foo(&a);

The 双指针可以是二维数组(或数组的数组,因为每个“列”或“行”不需要具有相同的长度)。我个人喜欢在需要传递一维数组时使用它:

void foo (char **c); //means I'm going to modify the elements of an array in foo.
{ (*c)[0] = 'f'; }

char *a;
a = malloc...
foo(&a);

对我来说,这有助于描述 foo 正在做什么。然而,这不是必需的:

void foo (char *c); //am I modifying a char or just passing a char array?
{ c[0] = 'f'; }

char *a;
a = malloc...
foo(a);

也会起作用。

根据第一个答案这个问题 https://stackoverflow.com/questions/1106957/passing-an-array-by-reference-in-c, if foo如果要修改数组的大小,则需要一个双指针。

人们可以清楚地看到如何三重指针(实际上)是需要的。就我而言,如果我传递一个指针数组(或数组数组),我会使用它。显然,如果您要传递到一个正在更改多维数组大小的函数,则需要这样做。当然,数组的数组的数组不太常见,但其他情况却很常见。

那么有哪些约定呢?这真的只是风格/可读性的问题,再加上许多人很难理解指针这一事实吗?


使用三重+指针会损害可读性和可维护性。

假设您在这里有一些函数声明:

void fun(int***);

嗯。参数是三维锯齿状数组,还是指向二维锯齿状数组的指针,还是指向数组的指针(例如,函数分配一个数组并在函数内分配一个指向 int 的指针)

让我们将其与以下内容进行比较:

void fun(IntMatrix*);

当然,您可以使用指向 int 的三重指针来对矩阵进行操作。但他们不是这样的。事实上,它们在这里作为三重指针实现的是不相关的给用户。

复杂的数据结构应该是封装的。这是面向对象编程的明显思想之一。即使在 C 语言中,你也可以在某种程度上应用这个原则。将数据结构包装在 struct 中(或者,在 C 中很常见,使用“句柄”,即指向不完整类型的指针 - 这个习惯用法将在后面的答案中解释)。

假设您将矩阵实现为锯齿状数组double。与连续的二维数组相比,它们在迭代时性能更差(因为它们不属于单个连续内存块),但允许使用数组表示法进行访问,并且每行可以具有不同的大小。

所以现在的问题是您现在无法更改表示形式,因为指针的使用是通过用户代码硬连接的,现在您陷入了较差的实现。

如果将其封装在结构中,这甚至不会成为问题。

typedef struct Matrix_
{
    double** data;
} Matrix;

double get_element(Matrix* m, int i, int j)
{
    return m->data[i][j];
}

只需更改为

typedef struct Matrix_
{
    int width;
    double data[]; //C99 flexible array member
} Matrix;

double get_element(Matrix* m, int i, int j)
{
    return m->data[i*m->width+j];
}

句柄技术的工作原理如下:在头文件中,声明一个不完整的结构体以及作用于该结构体指针的所有函数:

// struct declaration with no body. 
struct Matrix_;
// optional: allow people to declare the matrix with Matrix* instead of struct Matrix*
typedef struct Matrix_ Matrix;

Matrix* create_matrix(int w, int h);
void destroy_matrix(Matrix* m);
double get_element(Matrix* m, int i, int j);
double set_element(Matrix* m, double value, int i, int j);

在源文件中,您声明实际的结构并定义所有函数:

typedef struct Matrix_
{
    int width;
    double data[]; //C99 flexible array member
} Matrix;

double get_element(Matrix* m, int i, int j)
{
    return m->data[i*m->width+j];
}

/* definition of the rest of the functions */

世界其他地方不知道这意味着什么struct Matrix_包含并且它不知道它的大小。这意味着用户不能直接声明值,而只能使用指向的指针Matrixcreate_matrix功能。然而,用户不知道大小的事实意味着用户不依赖它 - 这意味着我们可以删除或添加成员struct Matrix_随意。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C 中的三重指针:这是风格问题吗? 的相关文章

  • Volatile.Read 和 Volatile.Write 背后的逻辑是什么?

    来自 MSDN Volatile Read 读取字段的值 在需要它的系统上 插入一个 阻止处理器重新排序内存的内存屏障 操作如下 如果在该方法之后出现读或写 代码 处理器无法移动它before这个方法 and Volatile Write
  • 编写此代码片段的有效方法是什么? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 更有效和 或更短地重写此代码以节省字节并显得不那么冗长的方法 if N 2 0 N 6 N 8 N 10 N 12 N 14 N 16 N
  • c# 从另一个类中的另一个静态事件引发事件

    需要帮助从另一个班级调用事件 我有已声明事件的课程 public class MxPBaseGridView GridView public event AddNewItemsToPopUpMenuEventHandler AddNewIt
  • 叮当错误?命名空间模板类的朋友

    以下代码在 clang 下无法编译 但在 gcc 和 VS 下可以编译 template
  • 并行化斐波那契序列生成器

    我正在学习并行化 在一项练习中 我得到了一些我应该提高性能的算法 其中之一是斐波那契数列生成器 array 0 0 array 1 1 for q 2 q lt MAX q array q array q 1 array q 2 我怀疑 这
  • 如果 JSON.NET 中的值为 null 或空格,则防止序列化

    我有一个对象需要以这样的方式序列化 即 null 和 空白 空或只是空格 值都不会序列化 我不控制对象本身 因此无法设置属性 但我知道所有属性都是字符串 环境NullValueHandling显然 忽略 只能让我找到解决方案的一部分 它 似
  • while循环中的变量初始化

    我有一个可以分块读取文件的函数 public static DataObject ReadNextFile 数据对象看起来像这样 public DataObject public string Category get set And ot
  • 为什么需要数字后缀?

    C 语言 我确信还有其他语言 需要在数字文字末尾添加后缀 这些后缀指示文字的类型 例如 5m是一个小数 5f是一个浮点数 我的问题是 这些后缀真的有必要吗 或者是否可以从上下文中推断出文字的类型 例如 代码decimal d 5 0应该推断
  • C# 编译器数字文字

    有谁知道 C 编译器数字文字修饰符的完整列表 默认情况下 声明 0 使其成为 Int32 声明 0 0 使其成为 Double 我可以在末尾使用文字修饰符 f 来确保某些内容被视为 Single 例如像这样 var x 0 x is Int
  • 子目录中的头文件(例如 gtk/gtk.h 与 gtk-2.0/gtk/gtk.h)

    我正在尝试使用 GTK 构建一个 hello world 其中包括以下行 include
  • 如何使用递归查找数字中的最小元素 [C]

    好的 所以我正在准备我的 C 考试 当谈到递归时我有点卡住了我是大学一年级的学生 这对我来说似乎有点困难 练习要求在给定的数字中使用递归函数我需要找到最小的元素 例如 52873 是 2 程序需要打印 2 include
  • 如何在 C# 中获取 Json 数组?

    我有一个像这样的 Json 字符串 我想将它加载到 C 数组中 当我尝试这样做时 我收到异常 我的字符串 customerInformation customerId 123 CustomerName Age 39 Gender Male
  • 无法为 wsdl 文件创建服务引用

    I have wsdl文件和xsd我本地机器上的文件 我想在项目中添加服务引用 我没有网络服务 我只有wsdl file 我收到以下错误 The document was understood but it could not be pro
  • 使用 OleDbCommandBuilder 时访问 SQL 语法错误

    我要在 C 中使用 OleDbDataAdapter 在 Access 数据库中插入数据 但收到错误消息INSERT INTO 命令中的语法错误 BackgroundWorker worker new BackgroundWorker Ol
  • C++ 到 C# 事件处理

    所以我有我的C WinForm 应用程序 我从中调用我的C CLI MFC dll图书馆 但也有一些events在我的 C 库上 甚至此事件也发生在该库的本机 非 CLI 部分 我需要从我的 C 应用程序调用一些代码 并获取一些有关此事件的
  • 如何使用 CSI.exe 脚本参数

    当你运行csi exe 安装了 Visual Studio 2015 update 2 您将得到以下语法 Microsoft R Visual C Interactive Compiler version 1 2 0 51106 Copyr
  • EnumDisplayDevices 与 WMI Win32_DesktopMonitor,如何检测活动监视器?

    对于我当前的 C 项目 我需要为在大量计算机上连接并处于活动状态的每个监视器检测一个唯一的字符串 研究指出了两种选择 使用 WMI 并查询 Win32 DesktopMonitor 以获取所有活动监视器 使用 PNPDeviceID 来唯一
  • 浮点字节序?

    我正在为实时海上模拟器编写客户端和服务器 并且由于我必须通过套接字发送大量数据 因此我使用二进制数据来最大化可以发送的数据量 我已经了解整数字节顺序以及如何使用htonl and ntohl为了规避字节顺序问题 但我的应用程序与几乎所有模拟
  • Xamarin.Forms UWP 项目中标题栏和选项卡之间令人恼火的空白

    我几乎是新手Xamarin Forms我正在开发一个相当简单的跨平台应用程序 该应用程序在 Android 中显示得足够好 但在 UWP 中却出现了一个愚蠢的空白 该项目由一个 TabbedPage 组成 其中包含 4 个 Navigati
  • 将 Swagger 与命名空间版本的 WebApi 结合使用

    我已经找到了如何使用基于名称空间的 WebAPI 版本这个班 https aspnet codeplex com SourceControl changeset view dd207952fa86 Samples WebApi Namesp

随机推荐

  • Firebase 推送通知不适用于 iOS

    我想使用 Firebase Cloud Messaging 实现推送通知 我已经按照说明设置了我的项目并上传了 APN 证书 我正在使用发送测试消息fcmtoken到我的真实设备 我在AppDelegate中的配置如下 func appli
  • 是否可以在不同的类中编写/包装异常处理组件(try、catch)?

    这是关于将异常处理逻辑包装在某种类中 在写c 的时候 代码中 很多时候我们需要根据客户端抛出的异常来捕获许多类型 变体 这导致我们在 catch 子句中 多次 编写类似类型的代码 在下面的示例中 我编写了 function 它可以以多种可能
  • Access 2010 SQL 查询仅在完整单词的字符串中查找部分匹配

    我希望这是一个简单的 我只是找不到如何获得我想要的结果 也许我在 SQL 中使用了错误的关键字 我正在搜索包含全名字段的员工表 该字段可以是 Sam 或 Evans 先生 或 Sam Evans 先生 我正在尝试查找与另一个包含名称字段的名
  • RecyclerView onClick 无法正常工作?

    我在片段中使用 RecyclerView 来显示带有网格格式文本的图像 Recycler 视图 grid item xml 如下所示
  • 队列管理和新线程

    在 Net 4 0 框架上使用 C 我有一个 Windows 窗体主线程 迄今为止唯一的一个 等待文件系统事件 然后必须对这些事件提供的文件启动一些预定义的处理 我计划执行以下操作 A1 当主进程启动时立即创建一个单独的线程 A2 让主线程
  • python中按特定顺序读取文件

    假设我的文件夹中有三个文件 file9 txt file10 txt 和 file11 txt 我想按这个特定顺序读取它们 谁能帮我这个 现在我正在使用代码 import glob os for infile in glob glob os
  • 无法获取 OLEObject 类的 Object 属性 - Excel Interop

    我用谷歌搜索了这个问题 但未能找到解决方案 如果文件保存为 xls 而不是 xlsm 则此代码有效 我使用的是 Office 2013 32 位 我编写了一个 COM 公开的 C 类库 Excel工作簿实例化一个对象并传入对当前工作簿的引用
  • 使用airflow的DataflowPythonOperator安排数据流作业时出错

    我正在尝试使用airflow 的DataflowPythonOperator 来安排数据流作业 这是我的 dag 运算符 test DataFlowPythonOperator task id my task py file path my
  • 如何从 Azure Key Vault 中的证书获取私钥?

    我在 Azure Key Vault 中有一个证书 我想从中提取私钥 根据微软文档 https learn microsoft com en us azure key vault certificates about certificate
  • Delphi 在保存对话框中覆盖现有文件

    我正在使用 TSaveDialog 组件通过单击按钮来保存文件 但是 我在保存现有文件名时遇到问题 通常 当您想要在 Windows 中保存现有文件时 会弹出一个消息框 询问您是否确实要覆盖该文件 TSaveDialog 组件的情况并非如此
  • 想要在 dojo 中创建一个组合框,其中下拉菜单和自动完成功能仅在用户输入 4 个字符后才启动

    我想在 dojo 中创建一个组合框 其中下拉菜单和自动完成功能仅在用户输入 3 个字符后才会启动 当前的默认设置将开始显示下拉菜单 并在用户输入第一个字符时自动完成 是否有任何属性可以实现此行为 我可以重载某些函数吗 或者我应该自己编写一个
  • GlassFish 3 + Maven + 远程部署

    我找不到任何关于如何通过 Maven 将简单的基于 Maven 的项目部署到远程 GlassFish 服务器的明确答案 mvn package xxx deploy 我认为只有 Cargo 插件支持 GlassFish 3 对吧 我在配置方
  • 为什么在 git reset (--mixed) 之前显式调用 git reset --soft

    在 git 文档 以及许多 SO 线程 中 建议使用这种重置方法 git reset soft HEAD go back to WIP state lt 2 gt git reset lt 3 gt 2 这将从提交历史记录中删除 WIP 提
  • UTF-8 格式的 JAVA Http POST 请求

    我的 J2EE 应用程序能够从 JSP 页面接收 POST 请求 这没有问题 但是如果我使用另一个java应用程序发送POST请求 收到的参数不是UTF 8字符串 这是我的代码 URL url new URL http localhost
  • 使用 std:fstream 如何拒绝对文件的访问(读和写)

    如何拒绝访问使用 fstream 打开的文件 我想在使用 fstream 读取 写入文件时无法访问该文件 您无法使用标准 fstream 来做到这一点 您必须使用特定于平台的函数 在 Windows 上 您可以使用创建文件 http msd
  • 创建 Android 锁屏应用程序。

    如何创建一个锁屏应用程序作为 Android 手机的锁 我确实找到了一个 但它的代码构造很差 如果我按下物理主页键 它就会解锁 使应用程序毫无意义 我确实遇到过一个论坛 指出 Android 4 x 中删除了一些阻止 home 按钮功能的方
  • Google 日历 API - 设计用于?

    我想使用 FullCalendar Javascript 实现 Google Calendar API 在开始编码之前 我有一些问题需要了解 Google Calendar API 的主要用途 如您所知 在创建和启用 API 之前有一些身份
  • 如何在nextjs中添加字体ttf文件

    我是 Nextjs 的新手 我想将自定义字体添加到我的项目中 我完全不知道如何做到这一点 我的字体位于 public fonts 中 我的 global css 文件是这样的 html body padding 0 margin 0 fon
  • 如何在jquery中向FormData添加变量?

    实际上我正在使用以下脚本来发布我的表单 var formData new FormData form driver information 0 ajax type POST url data formData success functio
  • C 中的三重指针:这是风格问题吗?

    我觉得 C 中的三重指针被视为 坏 对我来说 有时使用它们是有意义的 从基础开始 单指针有两个目的 创建数组 并允许函数更改其内容 通过引用传递 char a a malloc or void foo char c means I m go