c# 将字符串转换为二维数组时出现的问题

4sup72z8  于 2022-12-31  发布在  C#
关注(0)|答案(2)|浏览(334)

我会回到我的函数char **my_str_to_word_array(char *str),目的是在每个不可打印的ASCII字符处分离字符串,并将其包含在二维数组的新行中。
不可打印的ASCII字符应用作分隔符,且不应包含在行中。
示例:

char *test = "My name is John Doe.\nI have 0 GPA.\nI will survive." ;
char **array = my_str_to_word_array(test) ;

array[0] = "My name is John Doe." (zero terminated string)
array[1] = "I have 0 GPA." (zero terminated string)
array[2] = "I will survive." (zero terminated string)
array[3] = NULL

我有两个问题:
1.如果在我的测试main()中,my_str_to_word_array调用下面有一个printf(),那么传递给printf()的格式将包含在数组中,所以我得出结论,内存读取错误。
1.当我尝试free()阵列时,我得到一个错误:

double free or corruption (out)
[1]    33429 IOT instruction (core dumped)  ./libmy
size_t get_words_number(char const *str)
{
    size_t count = 0;
    const char *i = str;
    while (*i != 0) {
        if (isprint(*i)) {
            count++;
        }
        while (*i != 0 && isprint(*i)) {
            i++;
        }
        i++;
    }
    return count;
}

char **free_corrupted_array(char **array, size_t i)
{
    size_t j = 0;
    while (j < i) {
        free(array[j]);
        j++;
    }
    free(array);
    return NULL;
}

char **fill_array(char **array, const char *str, size_t word_count)
{
    size_t word_size = 0, j = 0;
    const char *i = str;
    while (j < word_count) {
        while (*i != 0 && isprint(*i)) {
            word_size++;
            i++;
        }
        array[j] = strndup(i - word_size, word_size);
        if (!array[j]) {
            return free_corrupted_array(array, j);
        }
        word_size = 0;
        j++;
        while (!isprint(*i)) {
            i++;
        }
    }
    array[j] = NULL;
    return array;
}

char **my_str_to_word_array(char const *str)
{
    char **word_array = NULL;
    size_t word_count = 0;
    if (!str) {
        return NULL;
    }
    word_count = get_words_number(str);
    word_array = malloc(word_count * sizeof(char *));
    if (!word_array) {
        return NULL;
    }
    word_array = fill_array(word_array, str, word_count);
    return word_array;
}
void my_free_word_array(char **word_array)
{
    if (!word_array) {
        return;
    }
    while (*word_array != NULL) {
        free(*word_array);
        word_array++;
    }
    free(word_array);
}
int main(int argc, char **argv)
{
    const char *test = "My name is John Doe.\nI have 0 GPA.\nI will survive.";
    char **word_array = my_str_to_word_array(test);
    while (*word_array != NULL) {
        printf("%s\n", *word_array);
        word_array++;
    }
    printf("Test print original size %lu\n", strlen(test));
    my_free_word_array(word_array);
    return 0;
}

并且输出:

My name is John Doe.
I have 0 GPA.
I will survive.
Test print original size %lu
Test print original size 50
double free or corruption (out)
[1]    33429 IOT instruction (core dumped)  ./libmy

你看到问题了吗?

ufj5ltwl

ufj5ltwl1#

错误:

  1. get_words_number超出了界限(相差1),可能会在字符串之后读取任意内存(请检查main中包含的示例)。
    1.您需要在阵列中增加一个插槽,以便放置终止NULL
    1.如果以后需要输入指针,请停止抖动(在my_free_word_arraymain的打印循环中)。
    建议:
    1.下一次通过包含所有需要的头来创建Minimal, Reproducible Example;
  2. strndup不是标准的(除非您有__STDC_ALLOC_LIB__并将__STDC_WANT_LIB_EXT2__定义为1)。
    1.您根本不需要free_corrupted_array函数。
#define _CRT_SECURE_NO_WARNINGS
#ifdef __STDC_ALLOC_LIB__
#define __STDC_WANT_LIB_EXT2__ 1
#else
#include <stdlib.h>
#include <string.h>
char *strndup(const char *str, size_t size)
{
    return strncpy(calloc(size + 1, 1), str, size);
}
#endif

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

size_t get_words_number(char const *str)
{
    size_t count = 0;
    const char *i = str;
    while (*i != 0) {
        if (isprint(*i)) {
            count++;
        }
        while (*i != 0 && isprint(*i)) {
            i++;
        }
        if (*i != 0) { // <--- This was missing
            i++;
        }
    }
    return count;
}

void my_free_word_array(char **word_array) // <--- Moved up
{
    if (!word_array) {
        return;
    }
    for (size_t i = 0; word_array[i] != NULL; ++i) { // <--- Stop thrashing word_array
        free(word_array[i]);
    }
    free(word_array);
}

char **fill_array(char **array, const char *str, size_t word_count)
{
    size_t word_size = 0, j = 0;
    const char *i = str;
    while (j < word_count) {
        while (*i != 0 && isprint(*i)) {
            word_size++;
            i++;
        }
        array[j] = strndup(i - word_size, word_size); 
        if (!array[j]) {
            my_free_word_array(array); // <--- No need for another free here
            return NULL;
        }
        word_size = 0;
        j++;
        while (!isprint(*i)) {
            i++;
        }
    }
    array[j] = NULL;
    return array;
}

char **my_str_to_word_array(char const *str)
{
    char **word_array = NULL;
    size_t word_count = 0;
    if (!str) {
        return NULL;
    }
    word_count = get_words_number(str);
    word_array = malloc((word_count + 1) * sizeof(char *)); // <--- You need a +1 here
    if (!word_array) {
        return NULL;
    }
    word_array = fill_array(word_array, str, word_count);
    return word_array;
}

int main(int argc, char **argv)
{
    char test[] = "My name is John Doe.\nI have 0 GPA.\nI will survive.\nThis will be removed from the string";
    *strrchr(test,'\n') = 0;
    char **word_array = my_str_to_word_array(test);
    if (word_array) {
        for (size_t i = 0; word_array[i] != NULL; ++i) { // <--- Stop thrashing word_array
            printf("%s\n", word_array[i]);
        }
        printf("Test print original size %zu\n", strlen(test));
        my_free_word_array(word_array);
    }
    return 0;
}
7uhlpewt

7uhlpewt2#

OP的代码错过了对 * 空字符 * 的检查。@Costantino Grana

候选get_words_number()校正和简化:

计数从“非单词”到“单词”的转换。
unsigned char*用于所有字符和is...()函数的定义用途。

#include <ctype.h>
#include <stdbool.h>

size_t get_words_number(char const *str) {
  const unsigned char *ustr = (const unsigned char *) str;
  size_t count = 0;
  bool previous_not_a_word = true;
  
  while (*ustr) {
    count += previous_not_a_word && isprint(*ustr);
    previous_not_a_word = !isprint(*ustr);
  }
  return count;
}

相关问题