memcpy() 在目标字符串中复制一些垃圾字符

memcpy() copies some garbage characters in the destination string

我正在尝试使用以下代码创建一个随机字符串生成器。

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

// Random string generator
void rand_str(char *dest, size_t length) {
    char charset[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    int charset_length = 62;

    while (length-- > 0) {
        size_t index = rand() % charset_length;
        *dest++ = charset[index];
    }
    *dest = '[=10=]';
}

int main ()
{
    int num_data = 5;
    int string_length;
    int max_string_length = 10;

    char data[num_data][string_length];
    int i = 0;
    while (i < num_data)
    {
        string_length = 3 + (rand() % max_string_length);
        char str[string_length];
        rand_str(str, string_length);
        short increment_avoider_flag = 0;
        for (int j = 0; j < i; j++)
        {
            if (!strcmp(data[j], str))
            {
                string_length = 3 + (rand() % max_string_length);
                char str[string_length];
                rand_str(str, string_length);
                increment_avoider_flag = -1;
                break;
            }
        }
        if (!increment_avoider_flag)
        {
            memcpy(data[i], str, sizeof(str));
            printf("%s\n", str);
            printf("%s\n\n\n", data[i]);
            i++;
        }
    }
    
}

上述代码的输出是

pn2QMwQbLq
pn2QMwQbLq~??


WqJ99NSq
WqJ99NSqLq~??


LDvi5z
LDvi5zSqLq~??


gxBewrk5rHr
gxBewrk5rHr??


DcDg
DcDgwrk5rHr??


这里的输出有两个问题。

  1. 如果创建的第一个字符串的长度 x 大于后面的字符串长度,memcpy 也会复制前一个字符串的剩余部分。例如第一个字符串是 pn2QMwQbLq,第二个字符串是 WqJ99NSq,但复制的字符串是 WqJ99NSqLq~??,其中有第一个字符串的附加 Lq
  2. 复制的字符串中有一些乱码。例如第一个原始字符串 pn2QMwQbLq 但复制的字符串 pn2QMwQbLq~?? 有额外的 ~??.

我不确定这里发生了什么,但似乎我在错误地声明或复制字符数组。请帮我解决这个问题。

由于字符串长度每次都在变化,所以需要动态定义,下面是对代码的2处修改。

int main ()
{
int num_data = 5;
int string_length;
int max_string_length = 10;
//char data[num_data][string_length];
char **data = (char **)malloc(num_data * sizeof(char *));   //change1
int i = 0;
while (i < num_data)
{
    string_length = 3 + (rand() % max_string_length);
    data[i] = (char*)malloc(string_length * sizeof(char));  //change2
    char str[string_length];
    rand_str(str, string_length);
    short increment_avoider_flag = 0;

如果你想生成没有任何内存泄漏的随机字符串。

以下代码实现了时间复杂度为 O(n)map 结构,其中 n 是字符串的长度。 这不是 map 的良好实现,但是在 C 中创建 map 将是一项繁重的任务。

优点:

  • 没有堆内存分配
  • 最终的随机字符串中没有重复字符

缺点:

  • 不是 map 的良好实现,因为时间复杂度应该是 O(log(n))

这里是try it online

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

const char *charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
void random_str(char *str, size_t len);
void random_str(char *str, size_t len)
{
    if (len == 0)
    {
        fprintf(stderr, "could not generate 0 length string\n");
        exit(1);
    }
    for (size_t i = 0; i < len; i++)
    {
        str[i] = charset[(rand() % 62)];
    }
    str[len] = 0;
}

#define NUM_DATA 5    
#define MAX_LEN 10

int main(void)
{
    char rdata[NUM_DATA][MAX_LEN + 1] = {0};
    srand(time(NULL));
    for (size_t i = 0; i < NUM_DATA;)
    {
        int flag = 1;
        random_str(rdata[i], MAX_LEN);
        for (size_t j = 0; j < i; j++)
            if (strcmp(rdata[i], rdata[j]) == 0)
                flag = 0;
        if (flag == 1)
        {
            printf("%s\n", rdata[i]);
            i++;
        }
    }
    return 0;
}

您的代码中存在多个导致未定义行为的问题:

  • 定义 char data[num_data][string_length]; 具有未定义的行为,因为 string_length 未初始化。您应该使用 char data[num_data][max_string_length + 1]; 以允许空终止符。

  • 3 + (rand() % max_string_length) 生成 3max_string_length + 2 范围内的 pseudo-random 整数,这似乎不正确。您应该使用 3 + (rand() % (max_string_length - 2) 来获取 3max_string_length 的范围。

  • char str[string_length]; 定义数组 str 一个字节对于 string_length 个字符的字符串来说太短了。

  • 如果发生碰撞,则无需生成新的随机字符串,尤其是在新的本地数组中。只需设置指标并跳出循环。

  • 您可以通过在 for 循环外定义 j 并使用 i == j 检查没有重复项来消除对指标的需求。

  • 您应该为随机数生成器设置种子以避免在每个 运行 生成相同的字符串。使用 srand(time(NULL));

意外输出是由未定义的行为引起的。

这是修改后的版本:

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

// Random string generator
void rand_str(char *dest, size_t length) {
    static const char charset[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    int charset_length = sizeof(charset) - 1;

    while (length-- > 0) {
        size_t index = rand() % charset_length;
        *dest++ = charset[index];
    }
    *dest = '[=10=]';
}

int main() {
    int num_data = 5;
    int max_string_length = 10;
    char data[num_data][max_string_length + 1];
    int i = 0, j;
    srand(time(NULL));
    while (i < num_data) {
        int string_length = 3 + (rand() % (max_string_length - 2));
        char str[string_length + 1];
        rand_str(str, string_length);
        for (j = 0; j < i; j++) {
            if (!strcmp(data[j], str))
                break;
        }
        if (j == i) {
            strcpy(data[i], str);
            printf("%s\n", str);
            i++;
        }
    }
    printf("\n");
    for (i = 0; i < num_data; i++) {
        printf("%s\n", data[i]);
    }
    return 0;
}