【问题标题】:Making a working copy of char array of unkown length制作长度未知的 char 数组的工作副本
【发布时间】:2020-07-19 21:55:25
【问题描述】:

将 MPLABX 5.35 与 XC16 v1.36 一起用于 PIC24FJ128GB204。有限的c背景,但正在学习。

我正在尝试编写一个函数,该函数采用 char 数组(大小未知)中的(指向 a)字符串并就地编辑它以使其右对齐并用字符填充它,直到它具有请求长度。 由于我也想为其他项目保留此功能,因此源数组的大小将是未知的,但用户(我)应保持 targetLength 小于数组的大小。

想象一下数组:

char example[20] = "test";

我希望能够将它传递给具有所需长度(例如,10 个字符,包括空终止)和填充字符“#”的函数,它应该将数组就地编辑为“#####测试”

我想出的代码(仅适用于某些场合,因此无法使用):

uint16_t fillStringRight(char * source, 
                    uint16_t targetLength, 
                    char filler)
{
    uint16_t sourceLength = strlen(source) + 1;

    if (sourceLength > targetLength){ 
        // source length is already longer than requested
        return 0;
    }

    uint16_t reqFiller = targetLength - sourceLength;

    strcpy(&source[reqFiller], source);
    memset(source, filler, reqFiller -1);
    return 1;
}

但是,在这种情况下:

char source[20] = "test";
fillStringRight(source, 6, ' ');

这不起作用。如果我理解正确,源和结果重叠,所以 strcpy 将覆盖空终止符,从而继续进一步写入内存,直到看门狗重新启动 PIC。

第一个问题:我的理解正确吗?

我想我应该复制源字符串而不是就地编辑它。但是,我不知道字符串的长度,所以我无法确定将用于复制的 char 数组的大小(除非我把它做得大得离谱)。我阅读了有关 malloc 以在堆中创建一个大小在运行时确定的变量,但也阅读了在微控制器上使用 malloc 的内容。我还不明白为什么,所以宁愿避开它,直到我理解得更好。

第二个问题:正确的方法是什么?我可以编写一个向后工作的函数(从最后一个位置的空终止符开始,然后向后工作),但这似乎有很多开销。有没有更好的办法?

【问题讨论】:

  • 尝试使用memmovememmove(&source[reqFiller], source, sourceLength)
  • @S.S.Anne 和 Stef1611:谢谢。 Memmove 是可行的选择。我没有想到用“重叠”这个词来描述我的问题,这样可以更容易地找到答案。谢谢。

标签: c memory strcpy


【解决方案1】:

来自man memmove(3)

内存区域可能会重叠:复制就像先将 src 中的字节复制到不与 src 或 dest 重叠的临时数组中一样,然后将字节从临时数组复制到 dest。

换句话说,有你想要的功能:)
试试memmove(&source[reqFiller], source, sourceLength); 等效的伪代码:

char *tmp = duplicate_string(source);
copy tmp to &source[reqFiller]; 

无关,但仅供参考:
1) strlen() 返回 size_t,而不是 uint16_t
2)&a[b] == &*(a +b) == (a + b) 所以&source[reqFiller] == source + reqFiller

【讨论】:

  • 谢谢,这确实解决了问题。在试图解决这个问题时,我没有想到“重叠”这个词。这将有助于我自己找到解决方案。
  • @Hello_World 只是出于好奇,是否有一种“简单”的方法可以在不保留大量内存的情况下进行复制(因为直到运行时我才知道字符串的大小) ?使用堆会是“最佳”选项吗?
  • 这完全取决于字符串的大小。默认堆栈大小虽然完全取决于平台/设置,但通常是几兆字节。根据经验,您只会遇到无限递归等签名堆栈溢出错误;不是大数组。假设您的编译器支持它们,您应该能够使用 C99 样式的 VLA 声明一个适当大小的数组。如果不是,是的,使用 malloc()。性能影响不应太大。至于制作副本,制作数组并调用memcpy() 可能与您将获得的一样快。
  • 顺便说一句,请注意 memmove() 不一定会创建临时副本。它只是表现得“好像”它确实如此。我相信(无需查找)它的实施方式不是标准化的。就是它的作用。
  • 我正在处理一张有 128KB 闪存的图片,所以我在这方面受到了限制。但是,我会查一下 VLA 是什么。谢谢。
猜你喜欢
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
  • 2017-05-30
  • 1970-01-01
  • 2015-03-04
  • 1970-01-01
  • 2019-12-01
相关资源
最近更新 更多