2017-01-25 11 views
0

私はここでは少し新しく、ポインタ、ポインタへのポインタ、および文字列についていくつか理解したかっただけです。ここでは、私がこれまでに書きとめたものです: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*の2つのポインタを指すタイプchar**のポインタを返したい場合、そこから各charの文字列にアクセスします。

出力が期待どおりではありません。私はCには比較的新しいので、まだ学んでいることがあります。

ありがとうございます、ありがとうございます。

+4

'LST [I] = malloc関数(はsizeof(CHAR)*(LEN/2))のように書かなければならない;' 1)文字列の長さが奇数である場合、これはあまり配分しません。2)結果文字列の2つの '\ 0 '終端文字のためのスペースも必要です。 2a)結果の文字列をヌル終了する必要があります。3) '(* lst)[0] = s [i];'これは間違っています。あなたの意図は何ですか? – wildplasser

+0

Cの文字列はヌルで終了する配列なので、それらのnullを処理するのを忘れたようです... –

+0

@wildplasser私は '*(lst [0])= s [i]'に変更しました。私は最初の 'char'配列にアクセスしようとしています – user2965071

答えて

2

まず、出力文字列内のNULLバイトのためのスペースを割り当てることを確認してください。

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]は最初の配列の2番目の文字を繰り返し上書きしていました。 2番目の配列は割り当てられて以来変更されておらず、ランダムなデータだけを含んでいました。

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つは、常に、二重終端ますが、我々はそれらの両方のための部屋を割り当てられているので、それは大丈夫です。ここで

+0

"配列の名前は、実際には最初の要素へのポインタです" - これは* not * trueです。式が 'sizeof'オペランドまたは単項'& '演算子のオペランドでない場合、または初期化に使用される文字列リテラルである場合、配列型*の式は最初の要素へのポインタへの*(" decay ")に変換されます宣言内の文字配列配列はポインタではなく、ピリオドです。 –

+0

Cを学ぶ人のために、あるいはポインタと配列がどのようにアルゴリズムで使われているかを理解しようとすると、配列を要素ゼロへのポインタとして考えるのが役に立ちます。私は言葉を「最善の考えです」と言い換えるように更新しましたが、私はその感情に立ちます。 –

+1

今、奇妙なサイズの文字列のためにそれを試してください... – wildplasser

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; 
} 
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]を変更しませんが、コピー

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]; 
+0

彼らは素晴らしい心について言う... – wildplasser

関連する問題