2015-12-21 4 views
-1

Следующий код из практического теста. Вопрос заключается в том, чтобы определить, правильна она или нет, и что она будет печатать, если она есть. Он компилирует и печатает, но я не понимаю, почему он печатает, что это такое.C программирование Массивы и указатели

У кого-нибудь есть идеи?

#include <stdio.h> 
int *getThreeNumbers() 
{ 
    int i; int a[3]; int *p; 
    for (i=0;i<3;i++) 
    { 
     printf("enter an integer\n"); 
     scanf("%d", a+i); 
    } 
    p=a; 
    return p; 
} 

int main() 
{ 
    int *q; int i; 
    q=getThreeNumbers(); 
    printf("the number you entered are:\n"); 
    for (i=0;i<3;i++) 
    printf("%d\n", q[i]); 
    return 0; 
} 

ответ

6

Не все, что компилируется, является хорошим кодом C. То, что вы здесь делаете, чрезвычайно опасно.

Вы объявляете массив в стеке в getThreeNumber(); и возвращаете указатель на него вызываемому (main в этом случае). int a[3] уничтожается, когда getThreeNumber() завершает выполнение, поэтому указатель, который передается обратно в main, может содержать мусор.

Это провоцирует не определено поведение.

#include <stdio.h> 
int *getThreeNumbers() 
{ 
    int i; 
    int a[3]; // a is created on the stack, it is only valid within 
       //the scope of this function 
    int *p; 
    for (i=0;i<3;i++) 
    { 
     printf("enter an integer\n"); 
     scanf("%d", a+i); 
    } 
    p=a; 

    return p; //a will die at this point and there is no guarantee 
       //that other values including garbage is not put in its place, 
       // but you are returning its address anyway. BAD IDEA 
} 

Правильный способ сделать это было бы выделить память в куче:

int *getThreeNumbers() 
{ 
    int i; 
    int *p = malloc(sizeof(int)*3); 
    for (i=0;i<3;i++) 
    { 
     printf("enter an integer\n"); 
     scanf("%d", &p[i]); 
    } 
    return p; 
} 

Помните, что вы должны освободить память в главном:

int main() 
{ 
    int *q; int i; 
    q=getThreeNumbers(); 
    printf("the number you entered are:\n"); 
    for (i=0;i<3;i++) 
    printf("%d\n", q[i]); 

    free(q); //not necessary in this case, but good form 
    return 0; 
} 

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

#include <stdio.h> 
void changeNumbers(int * p) 
{ 
    int i; 
    for (i=0;i<3;i++) 
    { 
     printf("enter an integer\n"); 
     scanf("%d", &p[i]); 
    } 
    printf("\n\n\n"); 
} 

int main() 
{ 
    int q[3]; int i; 
    for (i=0; i<3; ++i) q[i]=0; //initialize to 0 


    printf("the values before changing:\n"); 
    for (i=0;i<3;i++) 
    printf("%d\n", q[i]); 
    printf("\n\n\n", q[i]); 

    changeNumbers(q); 

    printf("the array after modification:\n"); 
    for (i=0;i<3;i++) 
    printf("%d\n", q[i]); 
    return 0; 
} 

Причина вторая программа хорошо ведет себя, потому, что массив никогда не разрушается, пока она не выходит из области видимости. Кадр стека changeNumbers() «сверху» основного, что означает, что адреса памяти ниже него безопасны от выхода из области действия и уничтожаются.

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

.

Во второй ситуации. когда changeNumbers() обращается к массиву, владелец массива (main) еще не выполнен! он все еще охлаждается и ждет changeNumbers(), чтобы завершить выполнение, прежде чем снова взять управление.

+0

«Правильный путь», возможно, должен быть «* A * правильным способом». Существуют и другие варианты, которые, возможно, лучше, например. имея вызывающего объекта, создайте массив из 3 целых чисел и передайте его как параметр. –

+0

@ M.M первоначально я упоминал о самом прямом сходном подходе, который позаботился о его проблеме. Забавно, что я предоставлял ему другую идиому перед тем, как вы прокомментировали – ForeverStudent

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