2017-01-25 5 views
0

Я немного новичок в C здесь и просто хотел понять несколько вещей о указателях, указателях на указатели и строки. Вот что я записал до сих пор: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

'LST [я] = таНос (SizeOf (Char) * (LEN/2));' 1) это будет слишком мало выделяться, если длина строки окажется нечетной. 2) вам также потребуется место для двух '' \ 0'' терминаторов в строках результата. 2a) вам нужно выполнить нулевое завершение результирующих строк. 3) '(* lst) [0] = s [i];' это просто неправильно. Ваше намерение здесь? – wildplasser

+0

Строки C представляют собой массивы с нулевым завершением, и похоже, что вы забыли обработать эти значения ... –

+0

@wildplasser Я изменил его на '* (lst [0]) = s [i]'. Я пытаюсь получить доступ к первому массиву 'char' – user2965071

ответ

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.

Имя массива лучше всего рассматривать как указатель на нулевой элемент. Итак, (*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; 

} 

Это решение «быстро и грязно» - один из массивов всегда получает двойную прекращенные, но это нормально, так как мы выделили комнату для обоих из них.

+0

«Имя массива - это, по сути, указатель на первый элемент» - это * not * true. Выражение типа массива * будет преобразовано * ("decay") в указатель на первый элемент, если выражение не является операндом 'sizeof' или унарных' & 'операторов, или если это строковый литерал, используемый для инициализации массив символов в объявлении. Массивы не являются указателями, периодом. –

+0

Для кого-то, кто изучает С, или, скорее, пытается понять, как в алгоритмах используются указатели и массивы, полезно использовать массив как указатель на нуль элемента. Я обновил формулировку, чтобы сказать «лучше всего думать», но я стою от настроения. –

+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

Смежные вопросы