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 中的通用数组元素交换 的相关文章

  • 如何在特定时间以毫秒精度触发 C# 函数?

    我有两台计算机 它们的时间通过 NTP 同步 确保时间仅相差几毫秒 其中一台计算机将通过 TCP 向另一台计算机发送一条消息 以在两台计算机上的未来指定时间启动某个 c 函数 我的问题是 如何在特定时间以毫秒精度 或更好 触发 C 中的函数
  • 将公历日期转换为儒略日期,然后再转换回来(随着时间)

    我正在编写一个程序 必须将当前的公历日期和时间转换为儒略日期 然后再转换回公历门 最终我需要添加能够添加年 月 日 小时 分钟和秒的功能 但我需要先解决这部分问题 现在我已经从公历日期转换为儒略日期 所以从逻辑上讲 我觉得我应该能够以某种方
  • 警告 C4800:“int”:强制值为 bool“true”或“false”(性能警告)

    我的代码中有这个问题 bool CBase isNumber return id MID NUMBER bool CBase isVar return id MID VARIABLE bool CBase isSymbol return i
  • Dapper 在执行时挂起

    我有一个 IDb连接 sql UPDATE 表名 SET json json lastupdate SYSDATE WHERE id id var param new DynamicParameters param Add json jso
  • 将 dataGridView 中选定的行作为对象检索

    我有一堂这样的课 public partial class AdressBokPerson public long Session get set public string F rnamn get set public string Ef
  • Monotouch全局异常处理

    我在野外发现了一只令人讨厌的虫子 但我无法确定它的具体情况 有没有办法拥有全局 Try Catch 块 或者有办法处理 Monotouch 中未处理的任何异常 我可以包起来吗UIApplication Main args 在 try cat
  • .NET 5 EF Core SaveChangesAsync 因错误而挂起

    尽管这个问题有很多结果 但没有一个真正给我明确的答案 每次我尝试通过 AddAsync 和 SaveChangesAsync 方法插入错误数据 例如重复的主键 时 我都会看到以下日志 执行 DbCommand 失败 15 毫秒 我还在 SQ
  • 配置:错误:无法运行C编译的程序

    我正在尝试使用 Debian Wheezy 操作系统在我的 Raspberry Pi 上安装不同的软件 当我运行尝试配置软件时 我尝试安装我得到此输出 checking for C compiler default output file
  • 更改 Xamarin.Forms 应用中顶部栏和底部栏(ControlsBar、StatusBar)的颜色

    无论如何 即使后面需要特定于平台的代码 也可以更改顶部栏 蓝色的 和底部栏 黑色的 的颜色吗 我希望添加对浅色和深色模式的支持 因此我希望能够在运行时更改它 有可能的 Android Using Window SetStatusBarCol
  • 如何构建一棵与或树?

    我需要一个支持 与 和 或 的树结构 例如 给定一个正则表达式 如ab c d e 我想把它变成一棵树 所以 一开始我们有两个 或 分支 它可以向下ab or c d e 如果你低头ab分支 你得到两个节点 a and b or a其次是b
  • C#:自定义转换为值类型

    是否可以将自定义类转换为值类型 这是一个例子 var x new Foo var y int x Does not compile 是否有可能实现上述情况 我需要超载一些东西吗Foo 您将必须重载强制转换运算符 public class F
  • 传递数组时在 C 中的函数参数中强制指定数组大小

    Context 在 C 中 我有一个以数组作为参数的函数 该参数用作该函数的输出 输出的大小始终相同 我会 让阅读代码的人清楚所需的大小 不过它已经在函数注释中了 理想情况下 编译会输出警告或错误 这样我就可以在编译时而不是运行时防止出现问
  • 选择合适的IDE

    您会推荐使用以下哪种 IDE 语言来在 Windows 下开发涉及识别手势并与操作系统交互的项目 我将使用 OpenCV 库来执行图像处理任务 之后 我将使用 win32 API 或 NET 框架与操作系统交互 具体取决于您建议的工具 性能
  • 连接到没有元数据的网络服务

    我想连接到此网络服务 https training api temando com schema 2009 06 server wsdl https training api temando com schema 2009 06 serve
  • 如何检测应用程序正在运行的 .NET 版本?

    我尝试使用Environment Version ToString 确定目标计算机上正在使用什么 NET 框架 但安装了 4 0 版本时 它说我正在使用 NET 2 0 如何检测目标计算机上正在运行的 NET Framework 版本 En
  • C 变量声明的效率 [重复]

    这个问题在这里已经有答案了 例如 在 C 中声明一个变量需要多长时间int x or unsigned long long var 我想知道它是否会让我的代码在类似的事情中更快 for conditions int var 0 code 这
  • 使用多态对象数组进行 JSON 反序列化

    我在涉及多态对象数组的 JSON 反序列化方面遇到问题 我已经尝试过记录的序列化解决方案here https stackoverflow com questions 5186973 json serialization of array w
  • Boost.asio和异步链,unique_ptr?

    我对异步编程不太熟悉 我有一个问题 我的问题如下 给出 boost asio 中 C 11 的 echo server 示例 http www boost org doc libs 1 60 0 doc html boost asio ex
  • 如何在 C 中创建最低有效位设置为 1 的掩码

    这个功能如何运作 最低有效 n 位设置为 1 的掩码 Example n 6 gt 0x2F n 17 gt 0x1FFFF 我根本不明白这些 尤其是 n 6 gt 0x2F 另外 什么是面膜 通常的方法是采取1 并将其左移n位 这会给你类
  • 如何使用 C# 为 azure devops 变量赋值

    我有 selenium C 测试脚本 可以从浏览器获取令牌 我有两个 azure devops 任务 一个用于执行 selenium 测试 另一个用于执行 API 测试 我想将 selenium 测试获取的令牌传递给 API 测试执行任务

随机推荐

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

    有一个 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 每个都有自己的指针类型 我想知道的是 是否有一种方法可以交换数组的两个元素 例如 无论数组类型如何