Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何使用一个循环连接/链接字符串数组中的单词?_C_Arrays_String - Fatal编程技术网

C 如何使用一个循环连接/链接字符串数组中的单词?

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

我有一个包含n个单词的数组。。我想把这些线连在一起。。 例如,如果数组具有以下字符串:“hello”“world”“stack77” 我希望函数返回:“helloworldstach7”有什么帮助吗?我如何在没有递归和一个循环的情况下执行类似的操作?我只能使用字符串库中的两个函数strcpy和strlen!! 任何想法!谢谢 我只需要使用一个循环

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的指针不是数组。根据数组的声明方式,可以重新分配数组,也可以不重新分配数组。接下来,您将使用什么存储来返回连接