我编写了一个程序,将char数组拆分为2D数组,作为函数状态定义下面的注释。但是,我在这段代码上收到了分段错误。有人可以帮忙找到原因吗?
my_strlen(str)
函数的工作方式与原始strlen(str)
函数的工作方式相同,并且完美无缺。并且char
数组的长度是有限的,所以我并不担心内存分配的效率。
char **my_str2vect(char *str) {
// Takes a string
// Allocates a new vector (array of string ended by a NULL),
// Splits apart the input string x at each space character
// Returns the newly allocated array of strings
// Any number of ' ','\t', and '\n's can separate words.
// I.e. "hello \t\t\n class,\nhow are you?" -> {"hello", "class,", "how", "are","you?", NULL}
int str_len = my_strlen(str);
char **output = malloc(sizeof(char *) * str_len); // Allocate a 2D array first.
if (**output) {
for (int a = 0; a < str_len; ++a) {
output[a] = malloc(sizeof(char) * str_len);
}
} else {
return NULL;
}
int i = 0;
int j = 0;
while (i < str_len) { // Put the characters into the 2D array.
int k = 0;
while ((str[i] == ' ' || str[i] == '\t' || str[i] == '\n') && i < str_len) {
++i;
}
while ((!(str[i] == ' ' || str[i] == '\t' || str[i] == '\n')) && i < str_len) {
output[j][k] = str[i];
++i;
++k;
}
output[j][k] = '\0';
++j;
}
output[j] = NULL;
return output;
}
答案 0 :(得分:1)
更正代码更改if (**output)
至if (output)
。
我认为你的实现不是内存效率高,而且更优雅 你分配的内存太多了。我试着在代码中解释输出char指针大小的上限。如果您想要具有确切的大小,则必须计算字符串中的单词。这样做可能会更好,但对于练习,我认为我们可以采用更简单的方式。
关于你的代码,我只能说:
'\0'
的结尾,这是一个不好的信号请参阅下面的改进实施(我使用标准C89):
#include<stdio.h>
#include <string.h>
#include<stdlib.h>
char** my_str2vect(char* s) {
// Takes a string
// Allocates a new vector (array of string ended by a NULL),
// Splits apart the input string x at each space character
// Returns the newly allocated array of strings
// Any number of ' ','\t', and '\n's can separate words.
// I.e. "hello \t\t\n class,\nhow are you?" -> {"hello", "class,", "how", "are","you?", NULL}
int s_size = strlen(s);
/*
* size of output is 1 if string contains non delimiters only
* size of output is 0 if string contains delimiters only
* size of output is strlen / 2 if string contains ...
* ...alternation of delimiter and non delimiter, and that is the max size
* so we allocate that size (upper bound)
*/
int max_output_size = (s_size / 2) + 1;
char **output = (char **) malloc(sizeof (char *) * max_output_size);
//initialize to NULL for convenience
int k;
for (k = 0; k < max_output_size; k++)
output[k] = NULL;
//work on a copy of s
char *str = (char *) malloc(s_size + 1);
strcpy(str, s);
//pointer for token and delimiters
char *ptr;
char delimiter[] = "\n\t ";
//initialize and create first token
ptr = strtok(str, delimiter);
//
int i = 0;
while (ptr != NULL) {
//allocate memory and copy token
output[i] = malloc(sizeof (char) * strlen(ptr) + 1);
strcpy(output[i], ptr);
//get next token
ptr = strtok(NULL, delimiter);
//increment
i++;
}
return output;
}
int main(int argc, char *argv[]) {
char **result = my_str2vect("hello \t\t\n class,\nhow are you?");
int i;
for (i = 0; result[i] != NULL; i++)
printf("%s\n", result[i]);
return 0;
}
答案 1 :(得分:1)
我尝试使用gdb
来确定问题。
它约为**output
控制。您应该检查*output
的地址,而不是指向指针的位置。您将在for循环中分配位置,直到字符串的长度。 可能会导致碎片整理。此外,1D char
数组应由const
传递为不可更改。相反,您应该使用代码段
// allocation (in the function)
// protoype: char** my_str2vect(char const* str)
int a;
char** output = malloc(str_len * sizeof(char *));
output[0] = malloc(str_len * str_len * sizeof(char));
for(a = 1; a < str_len; a++)
output[a] = output[0] + a * str_len;
// freeing (in main())
char ** x;
char const* str = "hello \t\t\n class,\nhow are you?";
x = my_str2vect(str);
free((void *)x[0]);
free((void *)x);
En passant,the source有助于更多地了解分配。
答案 2 :(得分:1)
调试器告诉你if (**output)
已损坏。它试图取消引用第一个输出数组位置中的指针。这是if
点上的垃圾。因此,seg错误。你想要if (output)
。当我修复此问题并使用strlen
代替您的重写时,它似乎工作正常。
制作输入字符串的一个副本并将其用于返回向量中的所有字符串要简单得多。您也可以使用strtok
来查找单词,但这不是线程安全的。
这是一个建议:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
char **split(char *s_org) {
size_t i;
// Skip initial whitespace, then copy everything else.
for (i = 0; s_org[i] && isspace(s_org[i]); ++i) /* skip */;
char *s = strdup(s_org + i);
size_t n_rtn = 0, size = 0;
char **rtn = malloc(sizeof *rtn);
for (i = 0;;) {
if (!s[i]) {
rtn[n_rtn] = NULL;
return realloc(rtn, (n_rtn + 1) * sizeof *rtn);
}
if (n_rtn == size) {
size = 2 * size + 1;
rtn = realloc(rtn, size * sizeof *rtn);
}
rtn[n_rtn++] = s + i;
while (s[i] && !isspace(s[i])) ++i;
if (s[i]) {
s[i++] = '\0';
while (isspace(s[i])) ++i;
}
}
}
int main(void) {
char **rtn = split(" hello \t\t\n class,\nhow are you?");
for (char **p = rtn; *p; ++p)
printf("%s\n", *p);
// Freeing the first element frees all strings (or does nothing if none)
free(rtn[0]);
free(rtn);
return 0;
}
这省略了对NULL
和malloc
的{{1}}返回的检查。但它们很容易添加。
您询问了代码中的“其他问题”。我在这里修了一些:
realloc
索引数组。size_t
进行不必要的调用。malloc
时,请避免使用strlen
。NULL
分配FOO *p = malloc(sizeof *p);
。它比FOO
更不容易出错。