[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