C函数将指针返回指针

时间:2017-01-25 14:11:28

标签: c arrays string pointers

我在这里对C有点新意,只想了解一些关于指针,指针指针和字符串的内容。这是我到目前为止写下的内容:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Return a pointer to an array of two strings. The first is the characters
   of string s that are at even indices and the second is the characters from
   s that are at odd indices */

char **parity_strings(const char *s) {
    int len = strlen(s);
    char **lst = malloc(sizeof(char*)*2);
    for(int i=0; i<2; i++){
        lst[i] = malloc(sizeof(char)*(len/2));
    }
    for(int i=0; i<len; i++){
        if(i%2==0){
            (*lst)[0]=s[i];
        }else{
            (*lst)[1]=s[i];
        }
    }
    return lst;

}

int main(int argc, char **argv) {
    char **r = parity_strings(argv[1]);
    printf("%s %s %s", r[0], r[1], argv[1]);
    return 0;
}

所以我想动态分配字符串数组和字符串本身所需的内存。我想知道我是否有正确的想法,希望返回类型为char**的指针,指针指向char*类型的两个指针,然后从那里访问每个char的指针串。

我的输出不符合预期。我对C来说比较新,所以我还有很多东西要学习。

任何帮助都将不胜感激,谢谢。

4 个答案:

答案 0 :(得分:2)

首先,确保为输出字符串中的空字节分配空间:

    for(int i=0; i<2; i++){
        /* Add an extra space for the \0 */
        lst[i] = malloc(sizeof(char)*(len/2 + 1));
    }

你的主要问题是奇怪的(*lst)[0]=s[i];部分。这与数组在C中的工作方式有关。

数组的名称最好被认为是指向第0个元素的指针。因此,(*lst)完全等同于编写lst[0]。所以(*lst)[0]只是用最新的偶数字重复覆盖第一个数组中的第一个字符,而(*lst)[1]只是重复覆盖第一个数组的第二个字母。第二个数组从未被分配,因为它被分配,只包含随机数据。

    for(int i=0; i<len; i++){
        if(i%2==0){
            /* i/2 makes sure every space gets filled,
            remember / means integer division in C */
            lst[0][i/2]=s[i];
        }else{
            lst[1][i/2]=s[i];
        }
    }
    /* Null terminate both strings, to be safe */

    /* terminate one early if the string was odd */
    lst[0][len/2 -len%2] = '\0';

    lst[1][len/2 ] = '\0';

    return lst;

}

这个解决方案“快速而且肮脏” - 其中一个数组总是被双重终止,但是没关系,因为我们为它们分配了空间。

答案 1 :(得分:1)

char **split_odd_even (char *org) {

char **lst;
size_t len, idx;

lst = malloc(2 * sizeof *lst);
len = strlen (org);

lst[0] = malloc ((len+3)/2);
lst[1] = malloc ((len+3)/2);

for (idx =0; org[idx]; idx++){
        lst[idx%2][idx/2] = org[idx];
        }

lst[idx%2][idx/2] = 0;
idx++;
lst[idx%2][idx/2] = 0;

return lst;
}

答案 2 :(得分:1)

这似乎意味着以下功能,如下面的示范程序所示

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char ** parity_strings( const char *s ) 
{
    size_t len = strlen( s );

    char **lst = malloc( 2 * sizeof( char* ) );

    lst[0] = ( char * )malloc( ( len + 1 ) / 2 + 1 );
    lst[1] = ( char * )malloc( len / 2 + 1 );

    size_t i = 0;

    for ( ; i < len; i++ )
    {
        lst[i % 2][i / 2] = s[i];
    }

    lst[i % 2][i / 2] = '\0';
    ++i;
    lst[i % 2][i / 2] = '\0';

    return lst;
}


int main(void) 
{
    char *s[] = { "A", "AB", "ABC", "ABCD", "ABCDE" };

    for ( size_t i = 0; i < sizeof( s ) / sizeof( *s ); i++ )
    {
        char **p = parity_strings( s[i] );

        printf( "%s %s %s\n", p[0], p[1], s[i] );

        free( p[0] );
        free( p[1] );
        free( p );

    }

    return 0;
}

它的输出是

A  A
A B AB
AC B ABC
AC BD ABCD
ACE BD ABCDE

至于你的函数,那么你错误地计算了新数组的长度,忘了用终止零附加它们。此外,当不再需要字符串时,您应释放所有已分配的内存。

在这些陈述中

(*lst)[0]=s[i];
(*lst)[1]=s[i];

应至少写成

(*lst)[i / 2] = s[i];
(*( lst + 1 ))[i / 2] = s[i];

答案 3 :(得分:0)

这是一种更直接使用指针代替索引的惯用C方式:

char **parity_strings(const char *s) {
    int len = strlen(s);
    char **lst = malloc(sizeof(char*)*2);
    for(i=0; i<2; i++){
        lst[i] = malloc((len+3)/2);  // reserve room for the terminating null
    }
    char *even = lst[0], *odd = lst[1];  // initializes pointers to even and odd parts
    for(;;) {                // tests inside the loop
        *even++ = *s++;      // directly processes s pointer!
        if (*s == '\0') break;
        *odd++ = *s++;       // every second is odd...
        if (*s == '\0') break;
    }
    *even = *odd = '\0';     // terminate the strings
    return lst;
}

这种方式确实忘记了初始s,但你不再需要它,而改变的只是一个本地指针。但由于必须返回lst,因此代码永远不会更改lst[i],而是使用副本