C 如何使用一个循环连接/链接字符串数组中的单词?
我有一个包含n个单词的数组。。我想把这些线连在一起。。 例如,如果数组具有以下字符串:“hello”“world”“stack77” 我希望函数返回:“helloworldstach7”有什么帮助吗?我如何在没有递归和一个循环的情况下执行类似的操作?我只能使用字符串库中的两个函数strcpy和strlen!! 任何想法!谢谢 我只需要使用一个循环C 如何使用一个循环连接/链接字符串数组中的单词?,c,arrays,string,C,Arrays,String,我有一个包含n个单词的数组。。我想把这些线连在一起。。 例如,如果数组具有以下字符串:“hello”“world”“stack77” 我希望函数返回:“helloworldstach7”有什么帮助吗?我如何在没有递归和一个循环的情况下执行类似的操作?我只能使用字符串库中的两个函数strcpy和strlen!! 任何想法!谢谢 我只需要使用一个循环 char *connect(char**words,int n){ int i=0; while(words){ strcpy(wor
char *connect(char**words,int n){
int i=0;
while(words){
strcpy(words+i,
我看到了许多解决方案,但它们都使用了其他字符串函数,我只想使用strcpy和strlen。如果只使用上述两个标准字符串函数,则该函数可以如演示程序所示
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * connect( char **words, size_t n )
{
size_t length = 0;
for ( size_t i = 0; i < n; i++ ) length += strlen( words[i] );
char *s = malloc( length + 1 );
size_t pos = 0;
for ( size_t i = 0; i < n; i++ )
{
strcpy( s + pos, words[i] );
pos += strlen( words[i] );
}
s[pos] = '\0';
return s;
}
int main( void )
{
char * s[] = { "Hello", " ", "World" };
char *p = connect( s, sizeof( s ) / sizeof( *s ) );
puts( p );
free( p );
}
如果只使用一个循环,那么函数可以按以下方式查看
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * connect( char **words, size_t n )
{
char *s = calloc( 1, sizeof( char ) );
if ( s != NULL )
{
size_t pos = 0;
for ( size_t i = 0; s != NULL && i < n; i++ )
{
size_t length = strlen( words[i] );
char *tmp = realloc( s, pos + length + 1 );
if ( tmp != NULL )
{
s = tmp;
strcpy( s + pos, words[i] );
pos += length;
}
else
{
free( s );
s = NULL;
}
}
}
return s;
}
int main( void )
{
char * s[] = { "Hello", " ", "World" };
char *p = connect( s, sizeof( s ) / sizeof( *s ) );
if ( p != NULL ) puts( p );
free( p );
}
#包括
#包括
#包括
字符*连接(字符**字,大小\u t n)
{
char*s=calloc(1,sizeof(char));
如果(s!=NULL)
{
大小\u t pos=0;
对于(大小i=0;s!=NULL&&i
除了使用strcpy外,还可以使用sprintf
。printf
系列中的每个函数返回实际输出的字符数,允许您在不进行额外函数调用的情况下计算最终字符串中的偏移量。现在,使用strcpy/strlen
方法没有什么错,事实上,这可能是首选方法,但请注意,在您给定的参数范围内,总是有多种方法可以进行操作。还请注意,printf
系列提供了丰富的格式优势,如果您需要在字符串串联的同时包含其他信息
例如,使用sprintf
连接每个字符串,同时将每个nc
中的字符数保存为将下一个字符串写入结果缓冲区buf
的偏移量,同时使用三元运算符控制基于循环计数器在字之间添加空格
,您可以执行以下类似操作:
char *compress (char **p, int n)
{
char *buf = NULL; /* buffer to hold concatendated string */
size_t total = 0; /* total number of characters required */
int nc = 0; /* number of chars added (counter) */
for (int i = 0; i < n; i++) /* get total required length */
total += strlen (p[i]) + 1; /* including spaces between */
if (!(buf = malloc (total + 1))) /* allocate/validate mem */
return buf; /* return NULL on error */
for (int i = 0; i < n; i++) /* add each word to buf, save nc */
nc += sprintf (buf + nc, i ? " %s" : "%s", p[i]);
*(buf + nc) = 0; /* affirmatively nul-terminate buf */
return buf;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *compress (char **p, int n)
{
char *buf = NULL; /* buffer to hold concatendated string */
size_t total = 0; /* total number of characters required */
int nc = 0; /* number of chars added (counter) */
for (int i = 0; i < n; i++) /* get total required length */
total += strlen (p[i]) + 1; /* including spaces between */
if (!(buf = malloc (total + 1))) /* allocate/validate mem */
return buf; /* return NULL on error */
for (int i = 0; i < n; i++) /* add each word to buf, save nc */
nc += sprintf (buf + nc, i ? " %s" : "%s", p[i]);
*(buf + nc) = 0; /* affirmatively nul-terminate buf */
return buf;
}
int main (void) {
char *sa[] = { "My", "dog", "has", "too many", "fleas." },
*result = compress (sa, sizeof sa/sizeof *sa);
if (result) { /* check return */
printf ("result: '%s'\n", result); /* print string */
free (result); /* free memory */
}
return 0;
}
char *compress (char **p, int n)
{
char *buf = NULL; /* buffer to hold concatendated string */
size_t bufsz = 0; /* current allocation size for buffer */
int nc = 0; /* number of chars added (counter) */
for (int i = 0; i < n; i++) { /* add each word to buf */
size_t len = strlen (p[i]) + 1; /* get length of word */
void *tmp = realloc (buf, bufsz + len); /* realloc buf */
if (!tmp) /* validate reallocation */
return buf; /* return current buffer */
buf = tmp; /* assign reallocated block to buffer */
bufsz += len; /* increment bufsz to current size */
nc += sprintf (buf + nc, i ? " %s" : "%s", p[i]);
}
*(buf + nc) = 0; /* affirmatively nul-terminate buf */
return buf;
}
示例使用/输出
$ ./bin/strcat_sprintf
result: 'My dog has too many fleas.'
内存/错误检查
$ valgrind ./bin/strcat_sprintf_realloc
==28175== Memcheck, a memory error detector
==28175== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==28175== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==28175== Command: ./bin/strcat_sprintf_realloc
==28175==
result: 'My dog has too many fleas.'
==28175==
==28175== HEAP SUMMARY:
==28175== in use at exit: 0 bytes in 0 blocks
==28175== total heap usage: 5 allocs, 5 frees, 68 bytes allocated
==28175==
==28175== All heap blocks were freed -- no leaks are possible
==28175==
==28175== For counts of detected and suppressed errors, rerun with: -v
==28175== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
在您编写的任何动态分配内存的代码中,对于所分配的任何内存块,您有两个责任:(1)始终保留指向内存块起始地址的指针,以便(2)在不再需要它时可以释放它
您必须使用内存错误检查程序,以确保您不会试图写入超出分配的内存块边界的内容,尝试读取未初始化的值或将条件跳转建立在未初始化的值上,最后确认您已释放分配的所有内存
对于Linux,valgrind
是正常的选择。每个平台都有类似的内存检查器。它们都很容易使用,只需运行程序即可
$ valgrind ./bin/strcat_sprintf
==27595== Memcheck, a memory error detector
==27595== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==27595== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==27595== Command: ./bin/strcat_sprintf
==27595==
result: 'My dog has too many fleas.'
==27595==
==27595== HEAP SUMMARY:
==27595== in use at exit: 0 bytes in 0 blocks
==27595== total heap usage: 1 allocs, 1 frees, 28 bytes allocated
==27595==
==27595== All heap blocks were freed -- no leaks are possible
==27595==
==27595== For counts of detected and suppressed errors, rerun with: -v
==27595== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认已释放所有已分配的内存,并且没有内存错误
仔细检查一下,如果还有其他问题,请告诉我
压缩
使用单个循环
正如对MarianD答案的评论中提到的,您可以使用单个循环,通过将每个单词添加到最终字符串来重新分配缓冲区,但这比获得所需的字符总数然后分配一次效率要低。然而,在很多情况下,这正是你需要做的。基本上,您只需获得每个单词的长度,然后使用realloc
而不是malloc
(或calloc
)为该单词分配内存(以及它与下一个单词之间的空间和nul字节)realloc
的作用与第一次分配的malloc类似,之后它调整缓冲区的大小以保持其当前内容
注意:切勿直接使用缓冲区(例如,buf=realloc(buf,newsize);
),而应始终使用临时指针。为什么?如果realloc失败,realloc
返回NULL
,这会导致您丢失对原始buf
的引用(例如,它将导致buf=NULL;
),这意味着您的原始buf
的地址丢失(并且您已经创建了内存泄漏)
综合起来,您可以执行以下操作:
char *compress (char **p, int n)
{
char *buf = NULL; /* buffer to hold concatendated string */
size_t total = 0; /* total number of characters required */
int nc = 0; /* number of chars added (counter) */
for (int i = 0; i < n; i++) /* get total required length */
total += strlen (p[i]) + 1; /* including spaces between */
if (!(buf = malloc (total + 1))) /* allocate/validate mem */
return buf; /* return NULL on error */
for (int i = 0; i < n; i++) /* add each word to buf, save nc */
nc += sprintf (buf + nc, i ? " %s" : "%s", p[i]);
*(buf + nc) = 0; /* affirmatively nul-terminate buf */
return buf;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *compress (char **p, int n)
{
char *buf = NULL; /* buffer to hold concatendated string */
size_t total = 0; /* total number of characters required */
int nc = 0; /* number of chars added (counter) */
for (int i = 0; i < n; i++) /* get total required length */
total += strlen (p[i]) + 1; /* including spaces between */
if (!(buf = malloc (total + 1))) /* allocate/validate mem */
return buf; /* return NULL on error */
for (int i = 0; i < n; i++) /* add each word to buf, save nc */
nc += sprintf (buf + nc, i ? " %s" : "%s", p[i]);
*(buf + nc) = 0; /* affirmatively nul-terminate buf */
return buf;
}
int main (void) {
char *sa[] = { "My", "dog", "has", "too many", "fleas." },
*result = compress (sa, sizeof sa/sizeof *sa);
if (result) { /* check return */
printf ("result: '%s'\n", result); /* print string */
free (result); /* free memory */
}
return 0;
}
char *compress (char **p, int n)
{
char *buf = NULL; /* buffer to hold concatendated string */
size_t bufsz = 0; /* current allocation size for buffer */
int nc = 0; /* number of chars added (counter) */
for (int i = 0; i < n; i++) { /* add each word to buf */
size_t len = strlen (p[i]) + 1; /* get length of word */
void *tmp = realloc (buf, bufsz + len); /* realloc buf */
if (!tmp) /* validate reallocation */
return buf; /* return current buffer */
buf = tmp; /* assign reallocated block to buffer */
bufsz += len; /* increment bufsz to current size */
nc += sprintf (buf + nc, i ? " %s" : "%s", p[i]);
}
*(buf + nc) = 0; /* affirmatively nul-terminate buf */
return buf;
}
注意:现在有5
分配,而不是1
如果您有任何问题,请告诉我。显示数组是如何声明的。我确信
'n'
被传递是有很好的理由的。是字数还是所有字符的总长度?strlen
可以用来告诉您在每次迭代中目标指针的前进量。lauren,请提供一个最小、完整且可验证的示例(请参见:)。提供必要的详细信息,包括您的代码和相关错误(如果有),这里的每个人都可以帮助您回答问题。好的,数组的问题是指向char的指针不是数组。根据数组的声明方式,可以重新分配数组,也可以不重新分配数组。接下来,您将使用什么存储来返回连接