【问题标题】:quick way to extract "valid" substring in c在c中提取“有效”子字符串的快速方法
【发布时间】:2021-08-22 01:12:56
【问题描述】:

我编写了两个函数来从字符串中提取“有效”子字符串,这意味着子字符串可能只包含字母和数字。但是,如果要检查的字符串很长,即使性能差距不是太明显,它们也会开始失去性能,这让我不太高兴。有没有更快的方法来“验证”字符串?这是我的代码:

#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <wchar.h>

wchar_t* validstr(wchar_t* src, wchar_t* cc, unsigned int* index) {
    wchar_t* valid = calloc(1, sizeof(wchar_t));
    while (isalpha(*cc) || isdigit(*cc)) {
        valid = realloc(valid, (wcslen(valid) + 2) * sizeof(wchar_t));
        wcscat(valid, (wchar_t[]) { *cc, 0 });
        ++* index;
        *cc = src[*index];
    }
    return valid;
}

wchar_t* validstr2(wchar_t* src) {
    wchar_t* valid = calloc(1, sizeof(wchar_t));
    while (isalpha(*src) || isdigit(*src)) {
        valid = realloc(valid, (wcslen(valid) + 2) * sizeof(wchar_t));
        wcscat(valid, (wchar_t[]) { *src, 0 });
        src++;
    }
    return valid;
}

int main() {
    wchar_t* str = L"valid10+(notvalidanymore";

    // usage for validstr()
    wchar_t current = str[0];
    unsigned int index = 0;
    printf("%ls\n", validstr(str, &current, &index));

    // usage for validstr2()
    printf("%ls\n", validstr2(str));
}

【问题讨论】:

  • 循环内的 realloc 会很慢。为什么不直接通过循环查找有效字符的数量,然后在循环后分配空间并复制数据?是否有理由需要在循环内重新分配?
  • 我只需 strdup 字符串,然后将所有应保留的字符移到前面,跳过不相关的字符。如果您绝对希望尽量减少分配的内存,请先计算剩余的字符数。
  • @Aconcagua 他的代码不会保留所有有效字符 - 它只是保留初始子字符串,但不包括第一个无效字符。所以他可以对字符串进行strdup,然后用字符串终止符替换第一个无效字符。这似乎是一个很好的方法 - 如果有 strdup 的宽字符版本。
  • 这就是我的想法:onlinegdb.com/qg24aTzxo 它仍然需要循环,但它只会在循环内递增,因此性能并不是真正的问题,因为时间完全被 calloc 所掩盖。实际上, calloc 似乎是一种浪费——如果你马上要重写它,你不需要初始化内存。 onlinegdb.com/gCvppGSBO 呢?
  • @JerryJeremiah 我的错,一直疏忽。在 POSIX 上,有 wcsdup 并且似乎 windows 也支持它。承认,不能保证一般可移植......

标签: arrays c string memory c-strings


【解决方案1】:

您应尽可能避免重新分配。

因此,您可以先计算与您相关的字符:

size_t length = 0
for(wchar_t* tmp = cc; *tmp && iswalnum(*tmp); ++tmp)
{
    ++length
}

请注意,isalnum 函数同时涵盖了 alpha 和数字 - 但在任何情况下您都应该使用宽字符函数(isw[...],请注意附加的 w)。

计算完后,您只需复制那些感兴趣的值:

wchar_t* valid = malloc((length + 1) * sizeof(wchar_t));
//                                ^ terminating null character!

memcpy(valid, cc, length*sizeof(wchar_t));
valid[length] = 0;

// for validstr:
memcpy(cc, src, length*sizeof(wchar_t));
*index = length;

我更喜欢malloc 而不是calloc,因为不需要对数组进行零初始化,无论如何它都会被覆盖。

请注意,validstr 的上述版本与您的实现略有不同:首先递增,然后复制字符,这会跳过 str 的第一个字符。我的版本从第一个字符开始复制。如果实际上是打算跳过第一个字符,那么从第一个字符开始复制,你就可以了:

memcpy(cc, src + 1, length);

请注意,无论如何,这个版本 (validstr(wchar_t*, wchar_t*, unsigned int*)) 对我来说似乎并不安全,您可能很容易超出 src 的范围,这将导致未定义的行为 - 除非您始终以任何方式保证 src至少与复制的子字符串一样长。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-20
    • 1970-01-01
    • 2013-03-04
    • 1970-01-01
    相关资源
    最近更新 更多