我试图从另一个数组创建一个数组,如果我有char *arr[100] = {"Hi", "&&", "hello", 0};
我想让它成为new[0] = "hi"; new[1] = "hello";
我的代码似乎不起作用。我该如何解决这个问题?
#include <stdio.h>
#include <string.h>
void split_by_word(char *av[], char **arr, char *word)
{
int i = 0;
int j = 0;
while (strcmp(*arr, word) == 0)
arr++;
if (!arr)
return ;
while (arr[i])
{
strcat(av[j], arr[i]);
if (strcmp(*arr, word) == 0)
j++;
i++;
}
}
int main()
{
char *av[100];
char *arr[100] = {"hi", "&&", "hello", 0};
memset(av, 0, sizeof(char *) * 100);
split_by_word(av, arr, "&&");
return 0;
}
给定数组
char *arr[] =
{
"Hello", "good",
"morning", "out",
"hello", "good",
"afternoon", 0
};
我分出时的输出(split_by_word(av, arr, "out"))
;
av[0] = "hello good morning";
av[1] = "hello good afternoon";
答案 0 :(得分:1)
您需要为新的2D数组分配空间以便开始。为简单起见,我分配了一个大小为100 x 10的文件。 *
此外,逻辑更简单,我会说,循环遍历你的数组,如果不 word
,那么复制它,否则什么都不做(跳过它,如果换句话说就是word
。
因此,一个基本的好例子是:
#include <stdio.h>
#include <string.h>
void split_by_word(char av[100][10], char **arr, char *word)
{
int i = 0, j = 0;
while(arr[i])
{
// if not 'word', copy
if(strcmp(arr[i], word))
strcpy(av[j++], arr[i]);
++i;
}
}
int main()
{
int i;
char av[100][10] = {{0}};
char *arr[100] = {"hi", "&&", "hello", 0};
split_by_word(av, arr, "&&");
for(i = 0; i < 2; ++i)
printf("%s\n", av[i]);
return 0;
}
输出:
Georgioss-MacBook-Pro:~ gsamaras$ gcc -Wall main.c
Georgioss-MacBook-Pro:~ gsamaras$ ./a.out
hi
hello
*对于2D动态分配的数组,我会这样做2d-dynamic-array-c。
答案 1 :(得分:1)
这里有一些代码似乎可以根据您修改过的问题的要求运行。我毫不怀疑可以通过一些努力来改进 - 特别是在split_by_word()
。您修改后的要求似乎会连接字符串,而您原来的要求确实不明确。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void split_by_word(char **av, char **arr, char *word)
{
while (*arr != 0)
{
if (strcmp(*arr, word) == 0)
av++;
else if (*av == 0)
*av = strdup(*arr);
else
{
size_t len = strlen(*av) + strlen(*arr) + 2; // 1 for null byte, 1 for blank
void *space = realloc(*av, len);
if (space == 0)
{
fprintf(stderr, "Memory allocation failed (%zu bytes)\n", len);
exit(EXIT_FAILURE);
}
*av = space;
strcat(*av, " ");
strcat(*av, *arr);
}
arr++;
}
*++av = 0; // Null terminate pointer list
}
static void free_words(char **words)
{
while (*words != 0)
{
free(*words);
*words++ = 0;
}
}
static void print_words(char **words)
{
for (int i = 0; words[i] != 0; i++)
printf("%d: [%s]\n", i, words[i]);
}
int main(void)
{
char *av[100] = { 0 };
char *arr1[100] = { "hi", "&&", "hello", 0 };
split_by_word(av, arr1, "&&");
print_words(av);
free_words(av);
char *arr2[] =
{
"Hello", "good",
"morning", "out",
"hello", "good",
"afternoon", 0
};
split_by_word(av, arr2, "out");
print_words(av);
free_words(av);
return 0;
}
示例输出:
0: [hi]
1: [hello]
0: [Hello good morning]
1: [hello good afternoon]
答案 2 :(得分:1)
您需要确保您了解您的arr
是指向字符串文字的指针数组,其中有标记,用于指示内容的分隔位置将数组放入由文字组成的单独字符串中,arr
最终由 sentinel nul终止。
一个问题是如何处理由arr
中的单词创建的字符串长度的变化。根据{{1}}中单词的长度,您如何确保组成结果数组的组合字符串有足够的空间?
您可以猜测并为结果数组中的每个元素设置一个静态存储大小(希望对于您需要分离的任何arr
足够大),或者您可以动态分配(根据需要分配/重新分配)。这样您就可以确保在结果数组中处理arr
的内容。
有很多方法可以执行此操作,您可以使用许多例程。无论如何,方法基本相同。读取arr
中的每个单词,确保结果字符串有足够的存储空间,然后将arr
中的单词连接到结果字符串。一种方法如下:
arr
高于#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXS 16
int split_by_word (char **res, char **arr, char *tok);
void *xrealloc (void *ptr, size_t psz, size_t *nelem, size_t inc);
int main (void) {
char *arr[] = { "Hello", "good",
"morning", "out",
"hello", "good",
"afternoon", 0 },
*res[sizeof arr/sizeof *arr] = { NULL },
*tok = "out";
if (split_by_word (res, arr, tok) > 0)
for (int i = 0; res[i]; i++) {
printf ("%s\n", res[i]);
free (res[i]);
}
return 0;
}
int split_by_word (char **res, char **arr, char *tok)
{
int aidx = 0, cidx = 0, ridx = 0; /* array, current and result index */
size_t szres = MAXS; /* current size of res[ridx] */
if (!res || !arr || !tok) return -1; /* validate parameters */
if (!(res[ridx] = calloc (szres, sizeof *(res[ridx])))) /* allocate result */
return -1;
while (arr[aidx]) {
if (strcmp (arr[aidx], tok) == 0) { /* separator found */
*(res[ridx] + cidx) = 0; /* nul-terminate */
ridx++; /* advance result index */
szres = MAXS; /* reset alloc size, alloc */
if (!(res[ridx] = calloc (szres, sizeof *(res[ridx]))))
return -1;
cidx = 0; /* reset current index */
}
else { /* append word from arr to res */
size_t len = strlen (arr[aidx]), /* get length */
reqd = cidx ? len + 2 : len + 1; /* add space and nulbyte */
if (cidx + reqd > szres) /* check space, realloc */
res[ridx] = xrealloc (res[ridx], sizeof *(res[ridx]), &szres,
cidx + reqd);
/* write word to result */
snprintf (res[ridx] + cidx, reqd, cidx ? " %s" : "%s", arr[aidx]);
cidx += reqd - 1; /* advance current index */
}
aidx++; /* advance array index */
}
*(res[ridx] + cidx) = 0; /* nul-terminate */
return ridx ? ridx : cidx ? 1 : ridx; /* return strings in results */
}
/** realloc 'ptr' to 'nelem' of 'psz' to 'nelem + inc' of 'psz'.
* returns pointer to reallocated block of memory with all new
* memory initialized to 0/NULL. return must be assigned to
* original pointer in caller.
*/
void *xrealloc (void *ptr, size_t psz, size_t *nelem, size_t inc)
{ void *memptr = realloc ((char *)ptr, (*nelem + inc) * psz);
if (!memptr) {
fprintf (stderr, "realloc() error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
} /* zero new memory (optional) */
memset ((char *)memptr + *nelem * psz, 0, inc * psz);
*nelem += inc;
return memptr;
}
会返回一个整数值,表示结果数组中的字符串数,或者出错时为split_by_word
。
示例使用/输出
-1
验证内存使用
如果你分配内存,你有责任保留一个指向每个块的begninning的指针,这样就可以在不再需要时释放它。在Linux上,$ ./bin/splitap
Hello good morning
hello good afternoon
是首选工具。只需通过它运行您的程序。 (每个操作系统都有类似的内存错误检查例程)
valgrind
您想要验证每个分配是否已被释放,是否可能发生内存泄漏,并且您使用已分配的内存的方式没有错误(例如无效的读/写等)。
答案 3 :(得分:0)
由于它(从您的声明中)看起来像您只想在新数组中存储指针,因此不需要strcat()
或strcpy()
。函数中的第一个循环似乎是跳过初始分隔符,但您可以在主循环中执行此操作。以下是代码的修改版本:
#include <stdio.h>
#include <string.h>
void split_by_word(char *av[], char **arr, char *word)
{
size_t i = 0;
size_t j = 0;
while (arr[i]) {
if (strcmp(arr[i], word)) {
av[j] = arr[i];
++j;
}
++i;
}
}
int main(void)
{
char *av[100];
char *arr[100] = {"hi", "&&", "hello", 0};
memset(av, 0, sizeof(char *) * 100);
split_by_word(av, arr, "&&");
for (size_t i = 0; av[i]; i++)
puts(av[i]);
return 0;
}
将arr
传递给split_by_word()
后,av
包含指向字符串文字"hi"
和"hello"
的指针:
λ> ./a.out
hi
hello
另一方面,如果您确实希望新数组包含字符串的副本,则必须声明av
以便为这些副本留出空间,并且您需要使用strcpy()
或者一些类似的函数,将字符复制到数组中。这是另一个完成此任务的版本。请注意,必须事先知道最大字符串的大小;为此,我#define
d为常数。另请注意,显示循环与前一循环略有不同。第一个显示循环一直持续到遇到NULL
指针,但在第二个版本中循环继续,直到遇到空字符串。输出与以前相同。
#include <stdio.h>
#include <string.h>
#define MAXWORD 100
void split_by_word(char av[][MAXWORD], char **arr, char *word)
{
size_t i = 0;
size_t j = 0;
while (arr[i]) {
if (strcmp(arr[i], word)) {
strcpy(av[j], arr[i]);
++j;
}
++i;
}
}
int main(void)
{
char av[100][MAXWORD] = { { 0 } };
char *arr[100] = {"hi", "&&", "hello", 0};
split_by_word(av, arr, "&&");
for (size_t i = 0; av[i][0]; i++)
puts(av[i]);
return 0;
}
我修改了之前的解决方案,以满足修订示例中建议的精确要求。常量MAXWORD
现在是MAXLEN
,并且足够大以容纳几个字。使用strcat()
代替strcpy()
,每次添加一个单词时,都会在字符串的末尾添加一个额外的空格字符。只有遇到分隔符字符串时,字符串索引j
才会递增。
请注意,没有检查可以确保av
中有一个新字符串的空间(当前最多可以容纳99个字符串,一个空字符串作为终结符),或者是新的空间字符串中的单词(999个字符加上'\ 0'终结符的空间似乎相当慷慨)。这里没有动态分配,如果您需要,Jonathan Leffler's solution可能更符合您的口味。
#include <stdio.h>
#include <string.h>
#define MAXLEN 1000
void split_by_word(char av[][MAXLEN], char **arr, char *word)
{
size_t i = 0;
size_t j = 0;
while (arr[i]) {
if (strcmp(arr[i], word)) {
strcat(av[j], arr[i]);
strcat(av[j], " ");
} else {
++j;
}
++i;
}
}
int main(void)
{
char av[100][MAXLEN] = { { 0 } };
char *arr[] =
{
"Hello", "good",
"morning", "out",
"hello", "good",
"afternoon", 0
};
split_by_word(av, arr, "out");
for (size_t i = 0; av[i][0]; i++)
puts(av[i]);
return 0;
}
以下是该计划的输出:
λ> ./a.out
Hello good morning
hello good afternoon
我不忍心离开这个而不添加对数组边界的一些检查,以避免在意外输入大小的情况下出现未定义的行为。以下是split_by_word()
函数的一个版本,如果有空间,则仅向av
添加新字符串,并且只有空格时才向字符串添加新字。如果没有足够的空间用于新单词,则该函数将跳至下一个分隔符或arr
的末尾,以先到者为准。我为要存储的最大字符串数添加了MAXNUM
常量,以替换以前版本中的硬编码100
。我毫不怀疑你可以改进这个功能。
#define MAXNUM 100
#define MAXLEN 1000
void split_by_word(char av[][MAXLEN], char **arr, char *word)
{
size_t i = 0;
size_t j = 0;
while ((j + 1) < MAXNUM && arr[i]) {
if (strcmp(arr[i], word)) {
/* Verify space for word + extra space */
if ((strlen(av[j]) + strlen(arr[i]) + 1) < MAXLEN) {
strcat(av[j], arr[i]);
strcat(av[j], " ");
} else { // No space: skip to next delimiter
++i;
while (arr[i] && strcmp(arr[i], word)) {
++i;
}
++j; // increment to next string
}
} else {
++j; // increment to next string
}
if (arr[i]) ++i; // increment i if not already at end
}
}