简体   繁体   English

C函数将指针返回指针

[英]C Function Returning a Pointer to a Pointer

I'm a bit new to C here, and just wanted to understand a few things about pointers, pointers to pointers, and strings. 我在这里对C有点陌生,只是想了解有关指针,指向指针的指针和字符串的一些知识。 Here's what I have written down so far: 到目前为止,这是我写下的内容:

#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;
}

So I want to dynamically allocate the memory needed for both the string array, and the strings themselves. 因此,我想动态分配字符串数组和字符串本身所需的内存。 I want to know if I have the right idea here by wanting to return a pointer of type char** which points to two pointers of type char* , and then from there access each char of the string. 我想知道我是否有正确的主意,想返回一个char**类型的指针,该指针指向两个char*类型的指针,然后从那里访问字符串的每个char

My output is not as expected. 我的输出与预期不符。 I'm relatively new to C, so there are things I'm still learning about. 我是C语言的新手,所以有些事情我还在学习中。

Any help would be appreciated, thanks. 任何帮助,将不胜感激,谢谢。

First, make sure to allocate space for the null byte in the output strings: 首先,确保为输出字符串中的空字节分配空间:

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

Your main problem was the weird (*lst)[0]=s[i]; 您的主要问题是怪异的(*lst)[0]=s[i]; part. 部分。 This has to do with how arrays work in C. 这与数组在C中的工作方式有关。

The name of an array is best thought of as a pointer to the zeroth element. 最好将数组的名称视为指向第零个元素的指针。 So, (*lst) is exactly equivalent to writing lst[0] . 因此, (*lst)等同于编写lst[0] so (*lst)[0] was just repeatedly overwriting the first character in the first array with the latest even letter, while (*lst)[1] was just repeatedly overwriting the second letter of the first array. 因此(*lst)[0]只是用最新的偶数字母重复覆盖第一个数组中的第一个字符,而(*lst)[1]只是重复覆盖第一个数组的第二个字母。 The second array was never modified since it was allocated, and just contained random data. 由于分配了第二个数组,因此从未对其进行修改,仅包含随机数据。

    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;

}

This solution is 'quick and dirty' - one of the arrays always gets double terminated, but that's ok since we allocated room for both of them. 这种解决方案“快速又脏”-数组之一总是被双终止,但这没关系,因为我们为它们两个分配了空间。

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;
}

It seems you mean the following function as it is shown in the demonstrative program below 看来您的意思是下面的演示程序中所示的以下功能

#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;
}

Its output is 它的输出是

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

As for your function then you incorrectly calculate the lengths of the new arrays and forgot to append them with the terminating zero. 至于您的函数,那么您会错误地计算新数组的长度,而忘记在它们的末尾附加零。 Also you should free all the allocated memory when the strings are not needed any more. 另外,当不再需要字符串时,您应该释放所有分配的内存。

And in these statements 在这些陈述中

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

should be written at least like 应该至少写成

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

Here is a more idiomatic C way directly using pointers instead of indexes: 这是一种直接使用指针而不是索引的更惯用的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;
}

This way indeed forget the initial s , but you do no need it again, and what is changed is just a local pointer. 这样的话确实会忘记初始的s ,但是您不再需要它了,更改的只是一个本地指针。 But as lst must be returned, the code never changes lst[i] but uses copies 但是由于必须返回lst ,因此代码永远不会更改lst[i]而是使用副本

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM