2010-11-22 3 views
9

Я прочитал несколько обсуждений, проходящий символ * в C.Передача обугленных * против гольца ** в качестве параметров функции в C

stackoverflow: passing-an-array-of-strings-as-parameter-to-a-function-in-c
stackoverflow: how-does-an-array-of-pointers-to-pointers-work
stackoverflow: whats-your-favorite-programmer-ignorance-pet-peeve
drexel.edu: Character arrays

Многих из они включают обсуждение массивов, но я хочу держаться подальше от этого.

Я пишу образец программы, чтобы научить себя прохождению char * и char ** в C. Это упражнение в передаче char * без использования (указателей) массивов. Также нет проблем с эффективностью исполнения. :-)

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

void get_args_works(int, char **, char **); 
void get_args_broken(int, char **, char *); 
char *get_string(int, char **); 

int main(int argc, char **argv) 
{ 
    char *string_works; 
    char *string_broken; 

    get_args_works(argc, argv, &string_works); 
    get_args_broken(argc, argv, string_broken); 

    printf("in main string_works (%p) = %s\n",string_works,string_works); 
    free(string_works); 

    printf("in main string_broken (%p) = %s\n",string_broken,string_broken); 
    free(string_broken); 
} 

void get_args_works(int argc, char **argv, char **string) 
{ 
    *string = get_string(argc, argv); 
    printf("in get_args_works %p string %s\n",*string,*string); 
} 

void get_args_broken(int argc, char **argv, char *string) 
{ 
    string = get_string(argc, argv); 
    printf("in get_args_broken %p string %s\n",string,string); 
} 

char * get_string(int argc, char **argv) 
{ 
    int i; 
    char *string; 
    string = malloc(40); 

    // placeholder in case -s switch not found below 
    strcpy(string,"-s switch not found below"); 

    for(i = 0; i < argc; i++) 
    { 
     if(argv[i][0] == '-') 
     { 
      switch(argv[i][1]) 
      { 
      case 's': 
       // release above malloc(40) for "-s switch not found below" 
       free(string); 
       // make room for storing variable 
       string = malloc(strlen(argv[++i]) + 1); 
       // the argv just after -s 
       strcpy (string,argv[i]); 
       break; 
      } 
     } 
    } 
    return string; 
} 

Вы можете также просмотреть same code on github

Приведенный выше код несколько документирован. main() объявляет две переменные char * и передает их в качестве параметров в соответствующие функции get_args().

Функция get_args() вызывает вызовы char * get_string(int, char **), используя тот же самый вызов (но другой способ получения возвращаемого значения).

get_string() отлично работает; он делает malloc() и возвращает указатель обратно на вызывающую функцию. Этот код работает, и каждая функция get_args() получает возвращаемое значение, как я ожидаю.

Но тогда, когда get_args() возвращает в main(), почему разыменованное значение указателя вернуться на главный (от get_args_works(), но не значение указателя (от get_args_broken())?

(т.е. я могу видеть что если я разыменования указателя (&string_works) при передаче в качестве параметра, это работает. Но почему? не char * string_broken уже указатель? почему это нужно «лишние» разыменования при передаче в качестве параметра?)

I В надежде на выигрышный ответ, объясняющий, как вы (да, вы) концептуализируете отправку char * в качестве параметра, а не получаете его как fu nction.

ответ

4
int get_args_broken(int argc, char **argv, char *string) 
{ 
    string = get_string(argc, argv); 
    printf("in get_args_broken %p string %s\n",string,string); 
} 

Вы только изменения локального (автоматический) переменной string. Это никак не видно вызывающему. Обратите внимание, что это означает, что вы освобождаете дикий указатель в основном.

Это неверно по той же причине:

int get_sum(int sum, int a, int b) 
{ 
    sum = a + b; 
} 

является; параметр скопирован по значению. Кроме того, вы не возвращаете int (как вы заявили, что хотите).

int get_args_works(int argc, char **argv, char **string) 
{ 
    *string = get_string(argc, argv); 
    printf("in get_args_works %p string %s\n",*string,*string); 
} 

является правильным (за исключением недостающего возврата). Вы не изменяете string, что было бы бессмысленно. Вы изменяете объект по адресу, где находится string, что в данном случае является char *.

EDIT: вам нужно было бы triple * argv, если бы была функция main, и вы хотели установить переменную этой функции на другой char **. НАПРИМЕР.

void trip_main(int *argc, char ***argv) 
{ 
    *argc = 10; 
    *argv = malloc(*argc * sizeof(char *)); 
} 

void caller() 
{ 
    char **argv; 
    int argc; 
    trip_main(&argc, &argv); 
} 
+0

hmmm. Я думаю, это может быть хорошим простым способом понять это. Он никак не говорит о char *. , но тогда почему нам не нужно втрое * argv? хммм. –

+0

OMG !!! Как я пропустил недопустимый тип возврата? ? Я сочиняю этот вопрос в течение * дней * ... !!!! d'ой !!!! –

+2

@ThunderRabbit: время, чтобы узнать, как включить дополнительные предупреждения от вашего компилятора или получить лучший компилятор. Если ваш компилятор не жалуется на функции, объявленные для возврата значения, которое возвращается без возврата значения, оно ... ну, не точно разбито, но не так полезно, как должно быть. Предупреждения компилятора - ваш друг - слушайте, как он говорит, и убедитесь, что он подробный. С GCC хорошей отправной точкой является «-Wall»; Обычно я использую «-Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition» (последнее, потому что я работаю над архаичным кодом). «-Wshadow» тоже хорош ... –

1

Одним из потребностей использовать указатель на указатель (здесь get_args_works()) является изменение (или возврат) более чем на переменной из функции, как и в C, это не представляется возможным вернуть более одной переменной.

get_args_works() works' coz, вы передаете указатель на указатель & Ссылка на него есть в вашем main().

Но в get_args_broken() вы проходите только указатель. Ничего плохого здесь, теперь вы делаете malloc() & возвратите выделенную память в строку get_args_broken(), все еще ничего плохого здесь. Но теперь эта помеченная ячейка содержит локальную & main() не имеет ссылки на этот var. Поэтому, когда вы разыскиваете char *string_broken; в main(), это может привести к неопределенному поведению.

Надеюсь, что это ясно.

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