2014-01-25 3 views
3

моей первоначальной проблемой является то, что я хочу написать функцию, которая может вернуть мне два значения. Я знаю, что могу это сделать, передав адрес двух аргументов функции и непосредственно вычислив их значения внутри этой функции. Но при проведении эксперимента происходит нечто странное. Значение, которое я получил внутри функции, не может пережить основную функцию:возвращают несколько значений из функции в C

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

void build(char *ch){ 
    ch = malloc(30*sizeof(char)); 
    strcpy(ch, "I am a good guy"); 
} 

void main(){ 
    char *cm; 
    build(cm); 
    printf("%s\n", cm); 
} 

Вышеупомянутая программа просто выдает мусор. Поэтому я хочу знать, что здесь не так. В конце концов, я хочу что-то вроде этого parse(char **argv, char **cmd1, char **cmd2), который может разобрать две команды для меня из исходной команды argv. Это было бы здорово, если бы кто-нибудь мог объяснить немного. Большое спасибо.

+0

'char ** ch ...' ... '* ch = malloc ...' ... 'strcpy (* ch ...' ... ' build (& cm) '... –

+0

Вы [указатель на указатель] (http://stackoverflow.com/questions/18306935/need-of-pointer-to-pointer/18307020#18307020) –

+0

Думайте об этом так , если функция принимает аргумент 'n', и указанная функция хочет присвоить новое значение' n' ('n = ...'), тогда требуется уровень косвенности, т. е. вам нужен указатель на 'n' (typeof_n *). Все аргументы функции в C передаются по значению, т. е. делается копия. Итак, поскольку вы проходите в 'char *', вам нужен указатель на один из них, т. е. на 'char **'. Затем вы можете написать '* n = malloc (size);'. Кроме того, 'sizeof char' определяется как' 1', поэтому нет необходимости в вызове 'malloc'. –

ответ

5

build() возьмите указатель ch по значению, то есть копия указателя передается функции. Поэтому любые изменения, которые вы вносите в это значение, теряются при выходе из функции. Поскольку вы хотите, чтобы ваша модификация указателя была видимой в контексте вызывающего, вам нужно передать указатель на указатель.

void build(char **ch){ 
    *ch = malloc(30*sizeof(char)); 
    strcpy(*ch, "I am a good guy"); 
} 

Кроме того, вам не нужно передавать указатели на функцию, потому что вам нужно вернуть несколько значений. Другой вариант - создать struct, который содержит значения, которые вы хотите вернуть как члены, а затем вернуть экземпляр указанного struct. Я бы рекомендовал этот подход в первом случае, если значения связаны, и имеет смысл объединить их вместе.


Вот повторное перечисление кода после фиксации ошибок:

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

void build(char **ch){ 
    *ch = malloc(30 * sizeof(char)); 
    strcpy(*ch, "I am a good guy"); 
} 

int main() {  // main must return int 
    char *cm; 
    build(&cm); // pass pointer to pointer 
    printf("%s\n", cm); 
    free(cm);  // free allocated memory 
    return 0;  // main's return value, not required C99 onward 
} 
+0

Может помочь указать: 'build (&cm);' –

+1

'// main должен возвращать пустоту' Я полагаю, вы имеете в виду' // main должен возвращать int' –

+0

@EdS. Спасибо .... – Praetorian

0

Это происходит потому, что в C, вы не можете переназначить адрес памяти указателя, поскольку она передается по значению.

Если вы действительно хотите это сделать, вы должны передать адрес указателя в функцию сборки.

См: Passing pointer argument by reference under C?

+1

«* вы не можете переназначить значение адреса памяти, на которое указывает указатель, потому что оно передается по значению. * "- Конечно, вы можете. Однако вы не можете присвоить новое значение самому указателю и ожидать, что он будет видимым для вызывающего. может присваивать новое значение тому, на что указывает указатель *, потому что у вас уже есть необходимый уровень косвенности. –

+0

Я полагаю, что это неправильно, я имел в виду, что вы не можете сделать указательный пункт другим адресом памяти, поскольку он передается по значению Конечно, вы можете изменить значение, вот в чем смысл использования указателя (предназначенного для каламбура) – George

+0

Это было бы правильно. Отредактируйте этот бит, и я удалю свой нижний план. –

1

Если вы хотите таНос внутри функции, необходимо передать адрес к внешнему указателю, так как ch внутри функции только локальная переменная, и его изменение не влияет на внешнюю cm переменная

void build(char **ch){ 
    *ch = malloc(30*sizeof(char)); 
    strcpy(*ch, "I am a good guy"); 
} 

void main(){ 
    char *cm; 
    build(&cm); 
    printf("%s\n", cm); 
} 

Но лучше не malloc внутри функции, а не просто написать, что вы хотите, чтобы область, на которую указывает указатель. Это общий способ, когда вам нужно предоставить буфер для получения данных на C. Таким образом, у пользователей будет выбор для распределения памяти самостоятельно или просто для использования локального буфера, и после этого вам не нужно освобождать память 'просто забыл в вашем примере

void build(char *ch){ 
    strcpy(ch, "I am a good guy"); 
} 

void main(){ 
    char *cm1; 
    cm1 = malloc(30*sizeof(char)); 
    build(cm1); 
    printf("%s\n", cm1); 

    char cm2[30]; 
    build(cm2); 

    printf("%s\n", cm2); 
    free(cm1);   // don't forget this 
} 
+0

ничего себе, спасибо большое. Это действительно чистый способ. Но не могли бы вы объяснить, почему здесь мы можем просто передать cm1 и cm2 по значению, а не по адресу? Благодарю. –

+0

, как я уже сказал, мы хотим иметь дело с данными, а не с указателем, поэтому мы передаем адрес в буфер/данные, вместо этого позволяя функции изменять указатель. Звонящие часто объявляют локальный массив вместо вызова malloc, потому что он быстрее и автоматически заканчивает свою жизнь после окончания действия, уменьшая шанс забыть освободить память, как ваш случай. Вы видите, memcpy или strcpy также является примером этого. Он принимает указатель на данные, а не на адрес указателя –

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