C 中的通用数组元素交换

2023-12-05

我现在意识到,在我的许多代码中,我将有 2 或 3 个这样的函数:

void swap(int* a, int* b)
{
    int t = *a;
    *a = *b;
    *b = t;
}

每个都有自己的指针类型。我想知道的是,是否有一种方法可以交换数组的两个元素,例如,无论数组类型如何?


可以,但是你必须告诉swap代码元素有多大:

void generic_swap(void *v1, void *v2, size_t size)
{
    char temp[size];
    memmove(temp, v1, size);
    memmove(v1, v2, size);
    memmove(v2, temp, size);
}

它使用 VLA(可变长度数组 - C99 的一项功能和 C11 的可选功能)作为临时空间。本地数组的大小,temp,在运行时由函数参数控制size。如果您不相信用户不会请求交换多兆字节的数据,则可以改用动态内存分配,或者仅在大小大于(例如 1 KB)时才使用动态内存分配。

Either:

void generic_swap(void *v1, void *v2, size_t size)
{
    size_t chunk = (size > 1024) ? 1024 : size;
    size_t offset = 0;
    char *s1 = v1;
    char *s2 = v2;
    char  temp[chunk];
    while (size > 0)
    {
        size_t length = (size > chunk) ? chunk : size;
        memmove(temp, s1 + offset, length);
        memmove(s1 + offset, s2 + offset, length);
        memmove(s2 + offset, temp, length);
        size -= length;
        offset += length;
    }
}

Or:

void generic_swap(void *v1, void *v2, size_t size)
{
    void *v3 = malloc(size);
    if (v3 != 0)
    {
        memmove(v3, v1, size);
        memmove(v1, v2, size);
        memmove(v2, v3, size);
        free(v3);
    }
}

循环版本避免了动态内存分配的开销,并且不会比在三个操作中全部复制慢多少。有多种方法可用于调整循环代码 - 另请参阅comments by rici如果您发现交换代码是瓶颈,则可以了解其他可以优化的方法。 您可以自由选择小于 1024 字节的大小; 64 或 128 也可能是可行的,并且函数中不一定需要 VLA。

交换两个整数:

int i = 37;
int j = 99;

swap_generic(&i, &j, sizeof(i));

交换两个数组char:

char data[80] = "A tabloid writer's nightmare on steroids";
char info[80] = "Obsequiousness will get you nowhere fast";

swap_generic(data, info, sizeof(data));

等等。请注意,数组的大小必须相同 - 或者更准确地说,您指定的大小必须是较小数组的大小才能安全。

您可以使用memcpy()代替memmove()如果你乐于危险地生活——尽管在这种情况下危险是有限的。 (如果你将一个对象与其自身交换,你会调用未定义的行为。否则,它是安全的。)memmove()总是有效;使用memcpy()通常有效。比起“大部分”,我更喜欢“总是”。


三种算法的测试工具

编译,例如:

gcc -O3 -g -std=c11 -Wall -Wextra -Werror -DUSE_GENSWAP_3 swap89.c -o swap89

当运行时Valgrind,代码获得了干净的健康证明。

Code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if !defined(USE_GENSWAP_1) && !defined(USE_GENSWAP_2) && !defined(USE_GENSWAP_3)
#define USE_GENSWAP_1
#endif

extern void generic_swap(void *v1, void *v2, size_t size);

#ifdef USE_GENSWAP_1
void generic_swap(void *v1, void *v2, size_t size)
{
    char temp[size];
    memmove(temp, v1, size);
    memmove(v1, v2, size);
    memmove(v2, temp, size);
}
#endif

#ifdef USE_GENSWAP_2
void generic_swap(void *v1, void *v2, size_t size)
{
    size_t chunk = (size > 1024) ? 1024 : size;
    size_t offset = 0;
    char *s1 = v1;
    char *s2 = v2;
    char  temp[chunk];
    while (size > 0)
    {
        size_t length = (size > chunk) ? chunk : size;
        memmove(temp, s1 + offset, length);
        memmove(s1 + offset, s2 + offset, length);
        memmove(s2 + offset, temp, length);
        size -= length;
        offset += length;
    }
}
#endif

#ifdef USE_GENSWAP_3
void generic_swap(void *v1, void *v2, size_t size)
{
    void *v3 = malloc(size);
    if (v3 != 0)
    {
        memmove(v3, v1, size);
        memmove(v1, v2, size);
        memmove(v2, v3, size);
        free(v3);
    }
}
#endif

static size_t min_len(size_t x, size_t y) { return (x < y) ? x : y; }

static void dump_long_buffer(const char *tag, size_t length, char buffer[length])
{
    int maxpadlen = strlen(tag) + sizeof(" = ") - 1;
    printf("%s = ", tag);
    size_t offset = 0;
    int padlen = 0;
    while (length > 0)
    {
        int linelen = min_len(length, 80 - maxpadlen - sizeof("[]\n"));
        printf("%*s[%.*s]\n", padlen, "", linelen, buffer + offset);
        offset += linelen;
        length -= linelen;
        padlen = maxpadlen;
    }
}

int main(void)
{
    int i = 37;
    int j = 99;

    printf("i = %d; j = %d\n", i, j);
    generic_swap(&i, &j, sizeof(i));
    printf("i = %d; j = %d\n", i, j);

    char data[80] = "A tabloid writer's nightmare on steroids";
    char info[80] = "Obsequiousness will get you nowhere fast";

    printf("data = [%s]\ninfo = [%s]\n", data, info);
    generic_swap(data, info, sizeof(data));
    printf("data = [%s]\ninfo = [%s]\n", data, info);

    char maxibuff1[2560];
    char maxibuff2[2560];

    for (size_t k = 0; k < sizeof(maxibuff1); k++)
    {
        maxibuff1[k] = k % 64 + '!';
        maxibuff2[k] = 'z' - k % 64;
    }

    /* The aligned output is mostly the result of serendipity */
    dump_long_buffer("maxibuff1", sizeof(maxibuff1), maxibuff1);
    dump_long_buffer("maxibuff2", sizeof(maxibuff2), maxibuff2);
    generic_swap(maxibuff1, maxibuff2, sizeof(maxibuff1));
    dump_long_buffer("maxibuff1", sizeof(maxibuff1), maxibuff1);
    dump_long_buffer("maxibuff2", sizeof(maxibuff2), maxibuff2);

    return 0;
}

示例输出(每种算法的结果相同):

i = 37; j = 99
i = 99; j = 37
data = [A tabloid writer's nightmare on steroids]
info = [Obsequiousness will get you nowhere fast]
data = [Obsequiousness will get you nowhere fast]
info = [A tabloid writer's nightmare on steroids]
maxibuff1 = [!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`]
            [!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`]
…
            [!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`]
maxibuff2 = [zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;]
            [zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;]
…
            [zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;]
maxibuff1 = [zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;]
            [zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;]
…
            [zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;]
maxibuff2 = [!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`]
            [!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`]
…
            [!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`]
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C 中的通用数组元素交换 的相关文章

  • 没有特殊字符的密码验证器

    我是 RegEx 的新手 已经进行了大量搜索 但没有找到任何具体内容 我正在编写一个验证密码字符串的正则表达式 可接受的字符串必须至少具有 4 种字符类型中的 3 种 数字 小写字母 大写字母 特殊字符 我对包含有一个想法 也就是说 如果这
  • 如何在 Cassandra 中存储无符号整数?

    我通过 Datastax 驱动程序在 Cassandra 中存储一些数据 并且需要存储无符号 16 位和 32 位整数 对于无符号 16 位整数 我可以轻松地将它们存储为有符号 32 位整数 并根据需要进行转换 然而 对于无符号 64 位整
  • std::vector 与 std::stack

    有什么区别std vector and std stack 显然 向量可以删除集合中的项目 尽管比列表慢得多 而堆栈被构建为仅后进先出的集合 然而 堆栈对于最终物品操作是否更快 它是链表还是动态重新分配的数组 我找不到关于堆栈的太多信息 但
  • 如何在 C# 中打开 Internet Explorer 属性窗口

    我正在开发一个 Windows 应用程序 我必须向用户提供一种通过打开 IE 设置窗口来更改代理设置的方法 Google Chrome 使用相同的方法 当您尝试更改 Chrome 中的代理设置时 它将打开 Internet Explorer
  • 如何从本机 C(++) DLL 调用 .NET (C#) 代码?

    我有一个 C app exe 和一个 C my dll my dll NET 项目链接到本机 C DLL mynat dll 外部 C DLL 接口 并且从 C 调用 C DLL 可以正常工作 通过使用 DllImport mynat dl
  • suhosin.mt_srand.ignore 在 PHP 中一致洗牌数组的解决方法?

    我有一个 PHP 脚本 需要随机化一个具有一致结果的数组 这样它就可以向用户呈现前几个项目 然后如果他们愿意 他们可以从同一个打乱的集合中提取更多结果 我目前使用的是这个 基于我相信的 Fisher Yates 算法 function sh
  • C++ 多行字符串原始文字[重复]

    这个问题在这里已经有答案了 我们可以像这样定义一个多行字符串 const char text1 part 1 part 2 part 3 part 4 const char text2 part 1 part 2 part 3 part 4
  • 重载 (c)begin/(c)end

    我试图超载 c begin c end类的函数 以便能够调用 C 11 基于范围的 for 循环 它在大多数情况下都有效 但我无法理解和解决其中一个问题 for auto const point fProjectData gt getPoi
  • 如何计算特定字符在字符串中出现的次数

    我正在尝试创建一个函数来查看数组中的任何字符是否在字符串中 如果是 有多少个 我尝试计算每一种模式 但是太多了 我尝试使用 Python 中的 in 运算符的替代方案 但效果不佳 function calc fit element var
  • 在 Unity 中实现 Fur with Shells 技术

    我正在尝试在 Unity 中实现皮毛贝壳技术 http developer download nvidia com SDK 10 5 direct3d Source Fur doc FurShellsAndFins pdf Fins 技术被
  • 两个静态变量同名(两个不同的文件),并在任何其他文件中 extern 其中一个

    在一个文件中将变量声明为 static 并在另一个文件中进行 extern 声明 我认为这会在链接时出现错误 因为 extern 变量不会在任何对象中看到 因为在其他文件中声明的变量带有限定符 static 但不知何故 链接器 瑞萨 没有显
  • 如何定义一个可结构化绑定的对象的概念?

    我想定义一个concept可以检测类型是否T can be 结构化绑定 or not template
  • x:将 ViewModel 方法绑定到 DataTemplate 内的事件

    我基本上问同样的问题这个人 https stackoverflow com questions 10752448 binding to viewmodels property from a template 但在较新的背景下x Bind V
  • 从 pygame 获取 numpy 数组

    我想通过 python 访问我的网络摄像头 不幸的是 由于网络摄像头的原因 openCV 无法工作 Pygame camera 使用以下代码就像魅力一样 from pygame import camera display camera in
  • 空指针与 int 等价

    Bjarne 在 C 编程语言 中写道 空指针与整数零不同 但 0 可以用作空指针的指针初始值设定项 这是否意味着 void voidPointer 0 int zero 0 int castPointer reinterpret cast
  • LINQ:使用 INNER JOIN、Group 和 SUM

    我正在尝试使用 LINQ 执行以下 SQL 最接近的是执行交叉联接和总和计算 我知道必须有更好的方法来编写它 所以我向堆栈团队寻求帮助 SELECT T1 Column1 T1 Column2 SUM T3 Column1 AS Amoun
  • 如何在 Linq to SQL 中使用distinct 和 group by

    我正在尝试将以下 sql 转换为 Linq 2 SQL select groupId count distinct userId from processroundissueinstance group by groupId 这是我的代码
  • 比较数组中的文件、从文本文件中删除行、函数、日志记录

    所以我创建了这两个数组 Approved Shares 和 Current Shares Reads Approvedshare txt and makes the txt file into an array public objFSO
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • 从 mvc 控制器使用 Web api 控制器操作

    我有两个控制器 一个mvc控制器和一个api控制器 它们都在同一个项目中 HomeController Controller DataController ApiController 如果我想从 HomeController 中使用 Dat

随机推荐

  • 是否有微数据标签来指定值是数字、字符串还是布尔值?

    有一个 HTML5 属性称为datetime指示值类型是日期时间 但我看不出有什么办法可以表明是否itemprop值在spantag 是字符串 布尔值或数字 我认为没有办法将此类信息包含在微观数据中 对吗 如果是这样 是否有某种原因应省略此
  • PHP解码json

    这里有人可以帮我用 php 解码 json 吗 我正在尝试解码 json api url 这是我现在所拥有的 string username someusername unconfirmed reward 0 08681793 send t
  • 通过 api/cli 启用和禁用 S3 复制规则

    我已在 S3 存储桶上设置了复制规则 以填充 preprod 存储桶以进行测试 这意味着我希望能够轻松地打开和关闭复制 并可能根据需要转储和刷新复制存储桶 我正在为此创建一个脚本 但很难找到一种在使用 AWS 控制台之外轻松打开和关闭复制规
  • TripleDES 加密和解密给出奇怪的结果

    我有一个有效的实施TripleDESCng 针对一些测试向量进行测试 但会发生以下情况 当我加密纯文本时This is a sample message 24 字节 因此这将是 3 个块 十六进制为546869732069732061207
  • DynamicJasper - 如何添加子报表作为列?

    Overview 我有一个 Java 类 其中有一个ArrayList必须打印到 jasperReport 作为子报表 我正在使用 DynamicJasper 库 关于这个问题的示例已被修改 因此可以复制 然而 实际情况的数据有所不同 Pr
  • 将单列分成 3 列,保留原始列 (R)

    我有一个独特的字符列 位于 DD HH MM 中 我试图将该列分成 3 个新的numeric列 我对单独函数的问题是它替换了原始列 并且我不知道如何传递多个条件SEP 请注意 并非每个观察结果都有 DD 我当前的代码如下所示 separat
  • IPC 性能:命名管道与套接字

    每个人似乎都说命名管道比套接字 IPC 更快 他们快了多少 我更喜欢使用套接字 因为它们可以进行双向通信并且非常灵活 但如果速度相当大 我会选择速度而不是灵活性 您将获得的最佳结果共享内存解决方案 命名管道仅比 16 好TCP 套接字 结果
  • C# 与 C++/CLI 中的 Unicode 字符串文字

    C char z u201D int i int z C CLI wchar t z u201D int i int z In C i正如我所期望的那样 变成了 8221 201D 另一方面 在 C CLI 中 它变成了 65428 FF9
  • Java 获取 MIB 中 OID 的名称/描述

    我正在编写一个网络管理系统 并且需要能够打印出从 SNMP 陷阱接收到的 OID 后面有意义的名称 由于该系统的性质 大小 对于正在使用的每台设备上的每个 MIB 手动将每个 OID 映射到有意义的名称并不是一个好主意 话虽如此 是否有一种
  • 更快的 iPhone PNG 动画

    目前 我的计时器上有一个 PNG 动画 每 0 01 秒触发一次 然而 性能并不是最佳的 而且动画速度明显很慢 我有超过 2000 张图片 有更好的方法来实现这一点吗 我在下面发布了与我的方法类似的内容 timer NSTimer sche
  • R 中向量的指数移动平均值

    我有一个简单的向量如下 x c 14 24 13 82 12 75 12 92 12 94 13 00 14 14 16 28 20 64 17 64 我正在尝试使用以下函数找到该向量的滚动 EMA library TTR y EMA x
  • matplotlib 错误 - 没有名为 tkinter 的模块 [重复]

    这个问题在这里已经有答案了 我尝试在 Windows 10 上通过 Pycharm IDE 使用 matplotlib 包 当我运行这段代码时 from matplotlib import pyplot 我收到以下错误 ImportErro
  • Java Swing、JComboBox 下拉列表在单击之前更改侦听器

    我有一个 JComboBox 其中包含 MIDI 文件列表 我想知道以下操作是否可行 当我单击 JComboBox 时 会打开一个下拉列表 当我将鼠标移到 midi 文件上时 它会播放 10 秒的示例声音 因此我知道该文件包含什么内容在我单
  • CakePHP 不使用我的模型

    我有这两个 CakePHP V 2 4 5 模型 class Owner extends AppModel public name Owner public hasMany array Car and class Car extends A
  • 使用python将csv转为json,json按行排列

    我想使用 Python 将 CSV 转换为一组 JSON 对象 并按行格式化 我尝试了下面的脚本 将几个 SO 答案放在一起 但格式如下 key value key value etc 我想将其格式化为 key value key valu
  • 更改 Microsoft Azure Blob - PHP 的默认服务版本

    this gt blobClient ServicesBuilder getInstance gt createBlobService azureString properties this gt blobClient gt getServ
  • Web Speech API Grammar 是否向开发人员公开?

    我目前正在对 Webkit 语音识别进行一些研究 我想创建一个特定于应用程序的语法文件 根据W3C的定义我写了下面的代码 但它似乎并没有显示出对这些单词的识别效果有所改善 您能提供一些帮助吗 var 识别 new webkitSpeechR
  • 当数组中元素的长度大于 2 时,出现“太多值无法解压(预期为 2)”

    也许问这个问题会很奇怪 因为我当然不明白 例如 如果我们有a 1 2 3 4 操作有效 for x y in a print x y 但是一旦我们向这些元组添加任何其他元素 a 1 2 3 4 5 6 for x y in a print
  • 循环和内置函数之间的数值不一致

    我正在尝试计算随机数数组的总和 但是 当我一次执行一个元素与使用内置函数时 结果之间似乎不一致 此外 当我降低数据精度时 误差似乎会增加 import torch columns 43 22 rows 44 torch manual see
  • C 中的通用数组元素交换

    我现在意识到 在我的许多代码中 我将有 2 或 3 个这样的函数 void swap int a int b int t a a b b t 每个都有自己的指针类型 我想知道的是 是否有一种方法可以交换数组的两个元素 例如 无论数组类型如何