我现在的问题是我已经为不同的单词占用了空间,但是在将其存储为数组时遇到了问题。即使有类似的帖子,对于我来说似乎也无济于事,而且我完全陷入了困境。我想保持这种格式(我不想更改函数的定义)。感谢所有帮助和评论!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int i, len = 0, counter = 0;
char ** p = 0;
for(i = 0; s[i] != '\0'; i++){
len++;
if(s[i] == ' ' || s[i+1] == '\0'){
counter ++;
for(i = 0; i < len; i++){
p[i] = s[i];
}
}
printf("%d\n", len);
printf("%d\n", counter);
return p;
}
int main() {
char *s = "This is a string";
int n;
int i;
for(i = 0; i < n*; i++){
//also not sure how to print this
}
}
答案 0 :(得分:0)
这是使用sscanf的解决方案。 scanf和sscanf将空格视为输入的结尾。我已经利用它使它为您工作。
char *str = (char*) "This is a string";
char buffer[50];
char ** p = (char**)malloc(1 * sizeof(*p));
for (int i = 0; str[0] != NULL; i++)
{
if (i > 0)
{
p = (char**)realloc(p, i * sizeof(p));
}
sscanf(str, "%s", buffer);
int read = strlen(buffer);
str += read + 1;
p[i] = (char*)malloc(sizeof(char)*read + 1);
strcpy(p[i], buffer);
printf("%s\n", p[i]);
}
由于此指针在两个维度上都在增长,因此每次找到新字符串时,我们都需要调整p
本身的大小,然后还应该重新调整其包含的新地址的大小。
答案 1 :(得分:0)
我现在的问题是我已经使用malloc为不同的单词占用了空间,但是在将其存储为数组时遇到了问题。
如果需要用于字符串集合的可寻址存储器,则需要一个指针集合以及每个所需指针的存储器。
在您的代码中:
p = (char**)malloc(counter*sizeof(char*));
您已经创建了指针集合,但是尚未在这些位置创建内存来容纳字符串。 (顺便说一下,演员不是必需的)
这是创建指针集合和每个指针的存储器的基本步骤:
//for illustration, pick sizes for count of strings needed,
//and length of longest string needed.
#define NUM_STRINGS 5
#define STR_LEN 80
char **stringArray = NULL;
stringArray = malloc(NUM_STRINGS*sizeof(char *));// create collection of pointers
if(stringArray)
{
for(int i=0;i<NUM_STRINGS;i++)
{
stringArray[i] = malloc(STR_LEN + 1);//create memory for each string
if(!stringArray[i]) //+1 room for nul terminator
{
//handle error
}
}
}
作为函数,它看起来可能像这样:(用calloc代替malloc来初始化空间)
char ** Create2DStr(size_t numStrings, size_t maxStrLen)
{
int i;
char **a = {0};
a = calloc(numStrings, sizeof(char *));
for(i=0;i<numStrings; i++)
{
a[i] = calloc(maxStrLen + 1, 1);
}
return a;
}
在您的split()
函数中使用它:
char** split(const char* s, int *n){
int i, len = 0, counter = 0, lenLongest = 0
char ** p = 0;
//code to count words and longest word
p = Create2DStr(counter, longest + 1); //+1 for nul termination
if(p)
{
//your searching code
//...
// when finished, free memory
答案 2 :(得分:0)
让我们从逻辑开始。
如何处理诸如A quick brown fox.
之类的字符串?我建议:
计算单词数,以及存储单词所需的内存量。 (在C语言中,每个字符串都以一个终止的nul字节\0
结尾。)
为指针和单词分配足够的内存。
复制源字符串中的每个单词。
我们有一个字符串作为输入,我们想要一个字符串数组作为输出。最简单的选择是
char **split_words(const char *source);
其中,如果发生错误,则返回值为NULL
,否则返回由NULL
指针终止的指针数组。所有这些都是一次动态分配的,因此在返回值上调用free()
将同时释放指针及其内容。
让我们根据上述要点开始实施逻辑。
#include <stdlib.h>
char **split_words(const char *source)
{
size_t num_chars = 0;
size_t num_words = 0;
size_t w = 0;
const char *src;
char **word, *data;
/* Sanity check. */
if (!source)
return NULL; /* split_words(NULL) will return NULL. */
/* Count the number of words in source (num_words),
and the number of chars needed to store
a copy of each word (num_chars). */
src = source;
while (1) {
/* Skip any leading whitespace (not just spaces). */
while (*src == '\t' || *src == '\n' || *src == '\v' ||
*src == '\f' || *src == '\r' || *src == ' ')
src++;
/* No more words? */
if (*src == '\0')
break;
/* We have one more word. Account for the pointer itself,
and the string-terminating nul char. */
num_words++;
num_chars++;
/* Count and skip the characters in this word. */
while (*src != '\0' && *src != '\t' && *src != '\n' &&
*src != '\v' && *src != '\f' && *src != '\r' &&
*src != ' ') {
src++;
num_chars++;
}
}
/* If the string has no words in it, return NULL. */
if (num_chars < 1)
return NULL;
/* Allocate memory for both the pointers and the data.
One extra pointer is needed for the array-terminating
NULL pointer. */
word = malloc((num_words + 1) * sizeof (char *) + num_chars);
if (!word)
return NULL; /* Not enough memory. */
/* Since 'word' is the return value, and we use
num_words + 1 pointers in it, the rest of the memory
we allocated we use for the string contents. */
data = (char *)(word + num_words + 1);
/* Now we must repeat the first loop, exactly,
but also copy the data as we do so. */
src = source;
while (1) {
/* Skip any leading whitespace (not just spaces). */
while (*src == '\t' || *src == '\n' || *src == '\v' ||
*src == '\f' || *src == '\r' || *src == ' ')
src++;
/* No more words? */
if (*src == '\0')
break;
/* We have one more word. Assign the pointer. */
word[w] = data;
w++;
/* Count and skip the characters in this word. */
while (*src != '\0' && *src != '\t' && *src != '\n' &&
*src != '\v' && *src != '\f' && *src != '\r' &&
*src != ' ') {
*(data++) = *(src++);
}
/* Terminate this word. */
*(data++) = '\0';
}
/* Terminate the word array. */
word[w] = NULL;
/* All done! */
return word;
}
我们可以通过一个小的测试main()
来测试上述内容:
#include <stdio.h>
int main(int argc, char *argv[])
{
char **all;
size_t i;
all = split_words(" foo Bar. BAZ!\tWoohoo\n More");
if (!all) {
fprintf(stderr, "split_words() failed.\n");
exit(EXIT_FAILURE);
}
for (i = 0; all[i] != NULL; i++)
printf("all[%zu] = \"%s\"\n", i, all[i]);
free(all);
return EXIT_SUCCESS;
}
如果我们编译并运行上面的代码,则会得到
all[0] = "foo"
all[1] = "Bar."
all[2] = "BAZ!"
all[3] = "Woohoo"
all[4] = "More"
这种方法的缺点(使用一个malloc()
调用来为指针和数据分配内存)是,我们不能轻易地增加数组。我们真的可以将其视为一大团块。
一种更好的方法,尤其是如果我们打算动态添加新单词时,是使用一种结构:
typedef struct {
size_t max_words; /* Number of pointers allocated */
size_t num_words; /* Number of words in array */
char **word; /* Array of pointers */
} wordarray;
不幸的是,这次我们需要分别分配每个单词。但是,如果我们使用一种结构来描述公共分配缓冲区中的每个单词,请说
typedef struct {
size_t offset;
size_t length;
} wordref;
typedef struct {
size_t max_words;
size_t num_words;
wordref *word;
size_t max_data;
size_t num_data;
char *data;
} wordarray;
#define WORDARRAY_INIT { 0, 0, NULL, 0, 0, NULL }
static inline const char *wordarray_word_ptr(wordarray *wa, size_t i)
{
if (wa && i < wa->num_words)
return wa->data + wa->word[i].offset;
else
return "";
}
static inline size_t wordarray_word_len(wordarray *wa, size_t i)
{
if (wa && i < wa->num_words)
return wa->word[i].length;
else
return 0;
}
想法是,如果您声明
wordarray words = WORDARRAY_INIT;
您可以使用wordarray_word_ptr(&words, i)
来获得指向第i
个单词的指针,或者如果还没有第i
个单词并且{{1} }以获取该单词的长度(比调用wordarray_word_len(&words, i)
快得多)。
在这里我们不能使用strlen(wordarray_word_ptr(&words, i))
的根本原因是char *
对数据区域(字指针将指向的区域)的访问可能会改变其地址。如果发生这种情况,我们必须调整数组中的每个指针。改用对数据区域的偏移量要容易得多。
此方法的唯一缺点是删除单词并不意味着数据区域相应缩小。但是,可以编写一个简单的“压缩器”功能,将数据重新打包到一个新的区域,以便将删除的单词留下的空洞“移动”到数据区域的末尾。通常,这不是必需的,但是您可能希望将一个成员添加到realloc()
结构中,说出从单词删除中丢失的字符数,以便可以在下次数据区将被试探性地进行压缩时否则调整大小。
答案 3 :(得分:0)
我编辑了您的代码,它现在可以正常工作:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char** split(const char* s, int *n);
char** split(const char* s, int *n) {
int i, len = 0, counter = 0;
char ** p = 0;
for(int i = 0; ; ++i) {
if(s[i] == '\0') {
break;
}
if(s[i] == ' ') {
counter += 1;
}
}
++counter;
p = (char **) malloc(counter * sizeof(char*));
for(int i = 0, c = 0; ; ++i, ++c) {
if(s[i] == '\0') {
break;
}
len = 0;
while(s[len + i + 1] != ' ' && s[len + i + 1] != '\0') {
++len;
}
p[c] = (char *) malloc(len * sizeof(char) + 1);
int k = 0;
for(int j = i; j < i + len + 1; ++j) {
p[c][k++] = s[j];
}
p[c][k] = '\0';
i += len + 1;
}
*n = counter;
return p;
}
int main() {
char *s = "This is a string";
int n;
int i;
char** split_s = split(s, &n);
for(i = 0; i < n; i++) {
printf("%s\n", split_s[i]);
}
}
但是我建议您进行一些清理。