[m-dev.] Help with C Interface

Fergus Henderson fjh at cs.mu.OZ.AU
Wed Mar 14 05:11:27 AEDT 2001


On 13-Mar-2001, Gustavo A. Ospina <gos at info.ucl.ac.be> wrote:
> Hello,
> 
> I'm doing a little experiment with the C interface. The main program is
> written in C and it calls Mercury code.
> 
> I use a container structure (binary tree) and a record structure
> (person), both of them implemented in Mercury.
> 
> The main program is a text user interface which uses a menu of options
> (add a person to the tree, delete a person, prints all the persons,
> etc).
> 
> Here a brief detail of the main algorithm in C:
> 
> /* Mercury types tree and person are bound to type MR_Word in C */
> typedef MR_Word m_tree;
> typedef MR_Word m_person;
> 
> /* Functions:
> c_init_tree();			/* Exported by Mercury in module tree.m */
> c_add_tree(Person, Tree);	/* Exported by Mercury in module tree.m */
> c_make_person(Id, Name);	/* Exported by Mercury in module person.m */
> 
> main()
> {    m_tree tr;
>      m_person pe;
>      int id;
>      char * name;
>      int opt
> 
>      tr = c_init_tree();
> 
>      while(<exit option not selected>){
>           opt = <read option from menu>;
>           switch(opt){
>           case 1: /* Addition */
>                <read id>;
>                name = (char *) malloc (MAX_NAME * sizeof(char));
>                <read name with gets()>;
>                pe = c_make_person(id, name);
>                tr = c_add_arbin(pe, tr);
>                free(name);
>                break;
>           /* Another cases */
>           }
>      }
>      return;
> }
> 
> There is a problem with the addition case. The string field in parameter
> 'pe', when a second person is added, is changed for all the persons
> contained in the tree. For exemple, if the first person read is (10,
> Pelé) and the second person read is (14, Cruyff), when I print all the
> persons I get:
> 
> Person 10 : Cruyff
> Person 14 : Cruyff
> 
> Pointer problem? yes...

Yes, the problem here is that you're calling free() to free the pointer,
but the Mercury code still has a reference to that pointer.

> I've tried using a pointer to the person
> structure (variable pe) and the result is the same. I must recall that
> fonction c_make_person is implemented in Mercury and exported, like
> this:
> 
> :- func make_person(int, string) = person.
> 
> make_person(Id, Name) = person(Id, Name).
>
> :- pragma export(make_person(in, in) = (out), "c_make_person").

A simple solution is to change to code for make_person/2
so that it copies the string onto the Mercury heap:

	make_person(Id, Name) = person(Id, NameCopy) :-
		copy(Name, NameCopy).

> I would like to know how could I copy the information of a person record
> (in the "adding" case of the main cycle) to avoid this side effect.

You can use the copy/2 predicate defined in the standard library module
builtin.m.

However, I think you only need to copy the string (as shown above),
not the whole record.

Cheers,
	Fergus.

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
                                    |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list