2014-12-17 1 views
2

После долгого времени, потраченного на создание этого кода, может кто-нибудь объяснить мне, почему мне нужно 2 звезды, когда я передаю указатель на строку в качестве аргумента функции ? Указатель по определению хранит адрес в памяти, где будет помещена определенная переменная. Таким образом, это переменная, которая имеет свой собственный адрес и по этому адресу адресует другую переменную. Хорошо. Поэтому, если я передаю указатель на функцию, я использую амперсанд, потому что я должен передать адрес указателя функции. Хорошо. Но тогда что происходит. Функция получает информацию, в которой в памяти находится этот указатель. Хорошо. Это то, что я понимаю. Я не понимаю, почему мне нужно две звезды, когда я определяю функцию и ее аргумент. Я передаю указатель на переменную char. Почему не void wpisuj (char * w). Почему wpisuj (char ** w). Распределение памяти для меня понятное - я зарезервировал память с malloc, и malloc возвращает адрес этой памяти, поэтому я поместил этот адрес как значение переменной w. И снова что-то я не понимаю, если * w является указателем и сохраняет адрес вновь созданного места в памяти, почему я использую * w для размещения там строки. Если это не будет * (* w)? Так как * w - адрес зарезервированной памяти, то * (* w) является содержимым этой памяти.Почему 2 звезды при передаче указателя на строку функции

Подведение итогов. Я не понимаю: 1) почему wpisuj (char ** w) вместо wpisuj (char * w) 2) почему strcpy (w, bufor) вместо strcpy ( (* w), bufor)

#include<stdlib.h> 
#include<stdio.h> 
#include<string.h> 
# define SIZE 256 

void wpisuj(char** pw){ 
    char bufor[256]; 
    scanf("%s", bufor); 
    int l; 
    l=strlen(bufor)+1; 
    *pw=(char*)malloc(l*sizeof(char)); 
    strcpy(*pw, bufor); 
} 


int main(){ 
    char* w; 
    wpisuj(&w); 
    printf("%s", w); 

    return 0; 
} 

И если я могу спросить о освобождении памяти. Я правильно думать, что это Corect количество звезд (как в коде ниже):

void free_memory(char **w){ 
    free(*w); 
} 

, но, если бы я освободил память в основной() я бы:

int main(){ 
    w=malloc(sizeof(buffer)+sizeof(char)); 
/* some code before */ 
    free(w); 
} 
+3

Две звезды, потому что это указатель на указатель .... – duffymo

+3

'*' = указатель. '**' = указатель на указатель. это все –

+0

Это поможет, если вы используете другое имя переменной в функции.Функция 'w' является указателем на' w' основного. Возможно, назовите его 'pw'. Тогда '* pw' в функции означает ту же переменную, что и' w' в main. –

ответ

4

Для станет ясно, рассмотрим следующую простую программу

#include <stdio.h> 

void f(int x) 
{ 
    x = x + 20; 
} 

int main(void) 
{ 
    int x = 10; 

    printf("Before the call f(x) x = %d\n", x); 

    f(x); 

    printf("After the call f(x) x = %d\n", x); 

    return 0; 
} 

Выход будет

Before the call f(x) x = 10 
After the call f(x) x = 10 

Как вы видите, х не было поменявшее в функции F, так как функция связана с копией объект x, определенный в основном.

Однако, если вы будете переписать функцию следующим образом

#include <stdio.h> 

void f(int *x) 
{ 
    *x = *x + 20; 
} 

int main(void) 
{ 
    int x = 10; 

    printf("Before the call f(x) x = %d\n", x); 

    f(&x); 

    printf("After the call f(x) x = %d\n", x); 

    return 0; 
} 

, то в этом случае выход будет

Before the call f(x) x = 10 
After the call f(x) x = 30 

, потому что мы перешли к функции адрес исходного объекта х и внутри функции был изменен исходный объект.

То же самое относится к указателю со своего поста.

Если вы определите указатель

char *p; 

в основной и передать его в качестве аргумента функционировать

void f(char *p); 

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

void f(char **p); 

и вы должны назвать его как

f(&p); 
4

причина wpisuj передана char**, так это то, что когда память распределена в функции и назначена *w, изменение отображается в вызывающей функции при возврате с wpisuj.

Если вы имели:

void wpisuj(char* w){ 
    char bufor[256]; 
    scanf("%s", bufor); 
    int l; 
    l=strlen(bufor)+1; 
    w=(char*)malloc(l*sizeof(char)); 
    strcpy(w, bufor); 
} 

Переход к w только локальное изменение. Вызывающая функция не видит изменения.

0

Ну, я объясню, что я понял по вашему вопросу: Всякий раз, когда вы хотите использовать функцию для изменения вашей переменной, вам необходимо отправить ее адрес, иначе внутри вашей функции вы измените локальную копию (локальная для функция), и, как только он вернется, он будет потерян.

1) В основном, в вашем главный, вы создаете указатель, который указывает на ничего и вы вызываете функцию wpisuj(), чтобы она указывала на что-то. Используя приведенную выше идею, вы должны отправить позицию памяти вашего указателя, чтобы функция могла измениться там, где она указывает. Если вы отправили только w вместо &w, вы отправили бы копию адреса туда, где он указал, и не смогли бы его изменить.

2) Ваша функция strcpy ожидает определенного ввода, который является адресом string, а не адресом указателя.Следовательно, вы используете *w, чтобы получить то, на что указывает ваш w.

0

Приведенный ниже код показывает другой способ сделать то же самое. Основное различие заключается в функции wpisujвозвращает указатель на недавно выделенную строку (который main затем присваивает w). Этот метод позволяет избежать использования указателя на указатель, так как wpisuj не нужно изменять main's копию w.

Другие отличия

  • ошибка проверки: возвращаемые значения из scanf и malloc не проверяются
  • нет утечек памяти: free(w) в конце
  • более высокий уровень безопасности: %255s в scanf мешает пользователю переполнения буфера

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

char *wpisuj(void) 
{ 
    char bufor[256]; 

    if (scanf("%255s", bufor) != 1) 
     return(NULL); 

    char *w = malloc(strlen(bufor) + 1); 

    if (w != NULL) 
     strcpy(w, bufor); 

    return(w); 
} 

int main() 
{ 
    char *w; 

    if ((w = wpisuj()) != NULL) 
    { 
     printf("%s\n", w); 
     free(w); 
    } 

    return 0; 
} 
0

Зачем мне нужен двойной указатель?

Это то, что я понимаю, ваш вопрос. Ответ таков: потому что, как и все фактические параметры (которые являются копиями значения, переданного вызывающим абонентом), указатели, переданные функции, будут удерживать свои значения в области, в которой они были фактически объявлены (что в данном случае является), не изменяя ничего в функции вызывающего абонента. И это не то, что вы хотите, потому что вы хотите изменить значение w.

Если вы что-то вроде этого:

void MyFunction(int* p) { 
    //`p`'s value, like `a`'s value, is NULL 
    *p=(char *)malloc(256*sizeof(char)); 
    //`p`'s value is the starting address of the buffer, but `a` didn't change 
    return; 
} 

int main() { 
    char* a; 
    a=NULL; 
    MyFunction(a); 
    return 0; 
    //`a`'s value is still NULL, because MyFunction() changed only its own copy of `a` 
} 

Ничего не происходит, потому что вы просто изменить адрес, на который указывает p внутри MyFunction().

Так что, как вы могли бы сделать для целых чисел:

void MyFunction(int* p) { 
    *p=1; 
    return; 
} 

int main() { 
    int a; 
    a=0; 
    MyFunction(&a); 
    printf("%d", a); 
    return 0; 
} 

сделать то же самое для указателей:

void MyFunction(int** p) { 
    *p=(char *)malloc(256*sizeof(char)); 
    return; 
} 

int main() { 
    char* a; 
    a=NULL; 
    MyFunction(&a); 
    return 0; 
} 

То, что я не понимаю, почему мне нужно две звезды, когда я определить функции и ее аргумента. Я передаю указатель на переменную char.

Почему не void wpisuj (char * w). Почему wpisuj (char ** w).

Посмотрите на свой код:

wpisuj(&w);

amperstand здесь разыменовывает указатель w. Это означает, что все выражение &w имеет значение адрес от w. Итак, то, что вы проходите, это адрес указателя на переменную char, которая является указателем указателю на переменную char. Что правильно: если вам нужно изменить целое число, вы передаете адрес целого числа. Если вам нужно изменить указатель, вы передаете адрес указателя. И поэтому даже правильно использовать wpisuj(char** w).

И снова что-то я не понимаю, если * w является указателем и хранит адрес вновь созданного места в памяти, почему я использую * w для размещения там строки.

Потому что вы не размещая строку: если w (внутри wpisuj()), как сказано выше является указателем на указатель на гольца, *w (внутри wpisuk()) является указателем на символ, который является эквивалентом *(&w) в main(), который является значением w в main(). Итак, что вы делаете, вы назначаете значение, возвращаемое malloc() вашей указателю w в main().

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