Pergunta

Isso vai soar como uma pergunta boba, mas eu ainda estou aprendendo C, por isso, tenha comigo. :)

Eu estou trabalhando em capítulo 6 do K & R (structs), e, até agora, através do livro ter visto grande sucesso. Eu decidi trabalhar com estruturas muito fortemente, e, portanto, fez um monte de trabalho no início do capítulo com o ponto e exemplos rect. Uma das coisas que eu queria tentar estava mudando a função canonrect (2ª Edição, p 131) trabalho através de ponteiros, e, portanto, void retornar.

Eu tenho esse trabalho, mas funcionou em um soluço que eu estava esperando vocês poderiam me ajudar com. Eu queria canonRect para criar um objeto retângulo temporário, executar suas alterações, em seguida, transferir o ponteiro é passado para o retângulo temporário, simplificando assim o código.

No entanto, se eu fizer isso, o rect não muda. Em vez disso, eu me encontro repovoamento manualmente os campos do rect Estou passada, que não funciona.

O código a seguir:

#include <stdio.h>

#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))

struct point {
    int x;
    int y;
};

struct rect {
    struct point lowerLeft;
    struct point upperRight;
};

// canonicalize coordinates of rectangle
void canonRect(struct rect *r);

int main(void) {
    struct point p1, p2;
    struct rect r;

    p1.x = 10;
    p1.y = 10;
    p2.x = 20;
    p2.y = 40;
    r.lowerLeft = p2; // note that I'm inverting my points intentionally
    r.upperRight = p1;

    printf("Rectangle, lower left: %d, %d; upper right: %d %d\n\n", 
        r.lowerLeft.x, r.lowerLeft.y, r.upperRight.x, r.upperRight.y);

    // can't pass a pointer, only a reference. 
    // (Passing pointers results in illegal indirection compile time errors)
    canonRect(&r); 
    printf("Rectangle, lower left: %d, %d; upper right: %d %d\n\n", 
        r.lowerLeft.x, r.lowerLeft.y, r.upperRight.x, r.upperRight.y);    
}

void canonRect(struct rect *r) {
    struct rect temp;
    temp.lowerLeft.x = min(r->lowerLeft.x, r->upperRight.x);
    temp.lowerLeft.y = min(r->lowerLeft.y, r->upperRight.y);
    temp.upperRight.x = max(r->lowerLeft.x, r->upperRight.x);
    temp.upperRight.y = max(r->lowerLeft.y, r->upperRight.y);

    r = &temp; // doesn't work; my passed-in rect remains the same

    // I wind up doing the following instead, to reassign all 
    // the members of my passed-in rect
    //r->lowerLeft = temp.lowerLeft;
    //r->upperRight = temp.upperRight;
}

Então, aqui estão as perguntas:

  1. Por que r = &temp; não funcionar? (I pensar isso é porque eu passar em uma referência em vez de um ponteiro;? Estou correto em pensar que as referências não são modificáveis ??mas ponteiros são)
  2. Por que eu poderia obter um engano erro de compilação ilegal se eu tentar passar um ponteiro para canonRect? (IE, se eu tivesse canonRect(*r); em main().)

Eu suspeito que eu já sei a resposta a # 1, mas # 2 perplexes-me - eu pensei que era legal para passar ponteiros em torno

.

De qualquer forma ... por favor, perdoe o newb C.

Foi útil?

Solução

Acho que o que você quer fazer é esta:

void canonRect(struct rect *r) {
    struct rect temp;
    temp.lowerLeft.x = min(r->lowerLeft.x, r->upperRight.x);
    temp.lowerLeft.y = min(r->lowerLeft.y, r->upperRight.y);
    temp.upperRight.x = max(r->lowerLeft.x, r->upperRight.x);
    temp.upperRight.y = max(r->lowerLeft.y, r->upperRight.y);

    *r = temp; 
}

No código acima você está definindo r * que é do tipo rect a temperatura que é do tipo rect.

Re 1: Se você quiser mudar o que r está apontando para você precisa usar um ponteiro para um ponteiro. Se isso é realmente o que você quer (ver acima, não é realmente o que você quer), então você tem que certificar-se de apontá-lo para algo na pilha. Se você apontar para algo que não é criado com 'novo' ou malloc em seguida, ele vai cair fora do escopo e você vai estar apontando para memória que não é mais usado para essa variável.

Por que não o seu trabalho de código com r = & temporário?

Porque r é de rect * tipo. Isso significa que r é uma variável que contém um endereço de memória que é a memória contém um rect. Se você mudar o que r está apontando para, tudo bem, mas isso não muda o passado na variável.

Re 2: * quando não usado em uma declaração do tipo é o operador unário dereference. Isso significa que ele irá procurar o que está dentro o endereço do ponteiro. Então, passando r * você não está passando um ponteiro em tudo. No rosto desde que r não é um ponteiro, que é uma sintaxe inválida.

Outras dicas

A sua importante notar também a variável 'struct temperatura rec' está indo para ir fora do escopo logo que termina método canonRect e você vai estar apontando para a memória inválido.

Parece que você está confundindo o operador 'dereference' (*) com o 'endereço de' operador (&).

Quando você escreve &r, que obtém o endereço de r e retorna um ponteiro para r (um ponteiro é apenas um endereço de memória de uma variável). Então, você realmente está passando um ponteiro para a função.

Quando você escreve *r, você está tentando dereference r. Se r é um ponteiro, que irá retornar o valor que r está apontando. Mas r não é um ponteiro, é um rect, então você vai ter um erro.

Para tornar as coisas mais confusas, o personagem * também é usada quando declarar variáveis ??de ponteiro. Nesta declaração da função:

void canonRect(struct rect *r) {

r é declarado para ser um ponteiro para um struct rect. Isso é completamente diferente de usar * assim:

canonRect(*r); 

Em ambos os casos, o caráter significa * algo completamente diferente.

Em primeiro lugar, K & R c não tem um conceito de "referências", apenas ponteiros. Os meios operador & "tomar o endereço do".


Em segundo lugar, o r em cannonRect() é uma variável local, e é não o r em main(). Alterando onde os pontos r locais não afeta o r na rotina de chamada.


Finalmente, como já se referiu a struct rect local é alocado na pilha, e sai do escopo no fechamento cinta,

Você pode querer ler sobre as diferentes formas parâmetros podem (conceitualmente) ser passados ??para as funções. C é chamada por valor , então quando você passar o ponteiro para um rect em a função que você está passando uma cópia do ponteiro. Qualquer altera a função marcas para o valor r diretamente (não indiretamente) não será visível para o chamador.

Se você quiser que a função de fornecer o chamador com uma nova estrutura, em seguida, há duas maneiras de fazê-lo: 1. Você pode retornar um rect: 2. você pode passar um ponteiro para um ponteiro para um rect em:

A primeira maneira seria mais natural:

struct rect* canonRect(struct rect* r)
{
  struct rect* cr = (struct rect*) malloc(sizeof(struct rect));
  ...
  return cr;
}

A segunda maneira seria:

void canonRect(struct rect** r)
{
  *r = (struct rect*) malloc(sizeof(struct rect));
}

eo chamador, então, usar:

   canonRect(&r);

Mas o chamador perde ponteiro originais que tinha, e você tem que ter cuidado para não vazar estruturas.

Seja qual for a técnica que você usa, a função terá de alocar memória para o novo struct na pilha usando malloc. Você não pode alocar o espaço na pilha por apenas declarar uma struct porque que a memória se torna inválida quando a função retorna.

2.Why pode eu recebo um engano erro de compilação ilegal se eu tentar passar um ponteiro para canonRect? (IE, se eu tivesse canonRect (* r);. Em main ())

Porque, não é o propósito de ponteiro .

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top