Difference of calls in main

0

Personal do I want to know the difference between these two calls?

inserir_inicio(&p, cria_no(0));

p = inserir_fim(p, cria_no(0));

When I try to switch to the first call style the code compiles but at the time of execution for everything.

//fim
tipo_lista* inserir_fim (tipo_lista * p, tipo_lista * novo_no)
{
//Se a lista estiver vazia
if(p==NULL)
    return novo_no;

tipo_lista* r = p; //Para manter a referencia ao primeiro elemento
while (p->prox != NULL)
{
    p = p->prox;
}
p->prox = novo_no;
return r;
}

//inicio
tipo_lista * inserir_inicio (tipo_lista * p, tipo_lista * novo_no)
{
novo_no -> prox = p;
return novo_no;
}

//main
int main(){
tipo_lista *p = NULL;

//inserir_inicio(&p, cria_no(0));
p = inserir_fim(p, cria_no(0));
p = inserir_inicio(p, cria_no(1));

imprime_lista(p);

return 0
}

Thank you

    
asked by anonymous 18.05.2017 / 17:15

2 answers

1

At first you are passing the pointer to p , so when you change the p value within the insert_initial function, you change the value of p outside the function.

While in the second you are copying the value of a variable to the variable inside the function, so when you change the p value within the function, you do not change the value of p out of function.

My details link

    
18.05.2017 / 17:19
1

If it's the kind of thing I'm thinking about, the reason is "reference emulation." As you may know, functions in C pass their parameters by value / copy. To emulate the pass by reference, you need to pass the pointers to the desired parameters and work with those pointers.

A short example to fix:

void badswap (int a, int b){
   int tmp;

   tmp = a;
   a = b;
   b = tmp;
}

void goodswap (int *ap, int *bp){
   int tmp;

   tmp = *ap;
   *ap = *bp;
   *bp = tmp;
}

To add an element to the end of a linked list, you pass the list head as a parameter because that head will not be modified. You will only modify the tail by adding an element at the end of it.

Already in the second, to add an element to the head of the list, you effectively have to modify the head of this list: it was in the location of memory X, now it will be in the location of memory Y. To do so, you will have that use the reference emulation.

I think to explain the cause of the error, I would have to do a table test, "mentally interpreting" the code itself. My best kick for now is that there should be some clutter of variables - imagine as if you had written something like *tmp = *bp; in the goodswap code. BUT, again, to point out for sure, I would have to see the complete code. These segmentation fault errors are difficult to explain in a "generic" way.

Tip : If possible, read the warnings of the compiler. They may contain useful insights about these errors. There are also other softwares, such as cppcheck , splint or even the gdb debugger .

EDIT:

I got home and tested the modified code on Clang. Well, as I imagined, the error is just in the parameter passing.

First, the way you did these two functions is different from what I had thought, but it's even cleaner and more functional. In this sense, much of my comment on reference emulation is unnecessary.

Secondly, going straight to the point, this is Clang's message:

testno.c:66:22: warning: incompatible pointer types passing 'tipo_lista **' (aka 'struct tipo_lista **') to parameter of type
      'tipo_lista *' (aka 'struct tipo_lista *'); remove & [-Wincompatible-pointer-types]
  p = inserir_inicio(&p,cria_no(2));
                     ^~
testno.c:37:43: note: passing argument to parameter 'p' here
tipo_lista * inserir_inicio (tipo_lista * p, tipo_lista * novo_no)
                                          ^
1 warning generated.

With this, the function expects a pointer, but you are passing a pointer-to-pointer. It's no wonder that it behaves erratically - if I'm not mistaken, in fact this would even be a case of undefined behavior: the compiler is free to do whatever it pleases. By "well understood," I mean "anything from firing nuclear missiles if there is hardware for it until the monitor melts."

BUT, assuming the compiler translates this as "obvious" as possible, it simply treats &p as if it were a memory location. "The programmer knows what he's doing." Because this memory location has not been legally allocated, it can be anywhere, most likely in a segment that does not belong to the program. And you will get a nice SIGSEGV .

I hope I have helped!

Post Scriptum : I left some nauseated tests out of my example in IDEONE; for example, if the memory was actually allocated. Even so, you can spend it ...

    
18.05.2017 / 19:56