# Objective-C: Casse-tête Malloc



## brainois (27 Décembre 2007)

Bonsoir à tous,
Il y bien longtemps que je n'ai plus pratiqué le C... Mais voici que je profite de ces quelques jours de congé entre Noël et nouvel an pour me mettre à Objective-C sur mon macbook! Naturellement, ce n'est pas l'aspect objet du langage qui pose problème, mais bien la si terrible et pourtant si excitante partie C et sa gestion mémoire...
Si j'exécute le programme avec la ligne de commande suivante:

```
./Fraction 3/4 1/3
```
Je m'attends à recevoir le résultat suivant:

```
3/4
1/3
The value of 3/4 + 1/3 is 1.08333
```
Mais j'obtiens:

```
3/4
1/3
The value of 13/12 + 13/12 is 1.08333
```
Le problème semble se situer à la ligne 27 du programme main qui combine printf avec plusieurs %s.
D'avance merci de m'éclairer de vos lumières
Voici donc le code incriminé:
le *header*:

```
#import <objc/Object.h>
@interface Fraction: Object
{
		int numerator;
		int denominator;
}
-(void) print;
-(void) setNumerator: (int) n;
-(void) setDenominator: (int) d;
-(void) setTo: (int) n over: (int) d;
-(int) numerator;
-(int) denominator;
-(double) toValue;
-(char*) toString: (char*) pString;
-(Fraction*) add: (Fraction*) f;
@end
```

L'*implémentation*:

```
#import "Fraction.h"
#import <stdio.h>
#import <string.h>
@implementation Fraction;
-(void) print
{
		printf(" %i/%i ", numerator, denominator);
}
-(void) setNumerator: (int) n
{
		numerator = n;
}
-(void) setDenominator: (int) d
{
		denominator = d;
}
-(void) setTo: (int) n over: (int) d
{
		numerator = n;
		denominator = d;
}
-(int) numerator
{
		return numerator;
}
-(int) denominator
{
		return denominator;
}
-(double) toValue
{
		if (denominator != 0)
				return (double) numerator / denominator;
		else 
				return 1.0;
}
-(char*) toString: (char*) pString
{
		sprintf(pString, "%i/%i", numerator, denominator);
		return pString;
}
-(Fraction*) add: (Fraction*) f
{
		numerator = numerator * [f denominator] + denominator * [f numerator];
		denominator *= [f denominator];
		return self;
}
@end
```

Le programme *main*

```
#import "Fraction.h"
#import <stdio.h>
#import <stdlib.h>
 
int main(int argc, char *argv[])
{
		if (argc < 2) {
				printf("Please specify the fraction as command line arguments.");
				return -1;
		}
		int n1, d1, n2, d2;
		char* str;
		Fraction* fraction1;
		Fraction* fraction2;
		// Create two instances of a Fraction
		fraction1 = [[Fraction alloc] init];
		fraction2 = [[Fraction alloc] init];
		// set the fractions as entered by the user
		sscanf(argv[1], "%i/%i", &n1, &d1);
		sscanf(argv[2], "%i/%i", &n2, &d2);
		[fraction1 setTo: n1 over: d1];
		[fraction2 setTo: n2 over: d2];
		// Display the sum of the two fractions
		str = (char*) malloc(20 * sizeof(char));
		printf("%s\n",[fraction1 toString: str]);
		printf("%s\n",[fraction2 toString: str]);
		printf("The value of %s + %s is %g\n", [fraction1 toString: str], [fraction2 toString: str], [[fraction1 add: fraction2] toValue]);
		free(str);
		[fraction1 free];
		[fraction2 free];
		
		return 0;
}
```


----------



## tatouille (28 Décembre 2007)

utilises tu objc 2?, normallement tu alloc retain et release des id/foundation types qui sont des objets, la la valeur est retain, ce que tu essayes de faire c est pas trop conseille, tu devrais plutot utiliser un nstring


----------



## brainois (28 Décembre 2007)

Salut tatouille...

Effectivement, j'utilise objc 2 sous léopard.

Comme objc est une couche objet sur C, je me dis que l'on peut programmer selon les règles du C. A l'avenir, j'utiliserai les facilités de objc en terme de gestion de chaînes, mais quand même, cet exemple me chipotte. Que se passe-t-il?

François


----------



## ntx (28 Décembre 2007)

brainois a dit:


> Que se passe-t-il?


Ton printf prend 3 arguments, il faudrait connaître l'implémentation de la fonction pour voir comment sont évalués ces 3 valeurs à afficher. Ton troisième argument appelle une fonction qui modifie fraction1 et il semble être évalué avant les deux autres d'où le 13/12. Ensuite tu utilises la variable str dans les deux premiers arguments d'où sûrement un mélange qui fait que cette chaîne prend la valeur 13/12 de fraction1 pour tes deux appels.
Je te conseillerais plutôt de faire tes "calculs" en dehors du printf et de n'envoyer comme argument que des valeurs fixes, de ne pas appeler de fonction qui modifie l'objet en même temps qu'il l'affiche.


----------



## brainois (28 Décembre 2007)

Merci ntx... Effectivement, c'est la conclusion à laquelle je suis arrivée juste avant de revenir sur le site macgeneration... Il semblerait que les arguments soient d'abord évalués avant d'être substitués dans le chaîne de caractères. De plus, les arguments qui ne sont pas de simple "getter" semblent être évalués en premier.
Je dois avouer que ce comportement est plutôt étrange...
Merci pour ta réponse!
François


----------



## Didier Guillion (28 Décembre 2007)

brainois a dit:


> Merci ntx... Effectivement, c'est la conclusion à laquelle je suis arrivée juste avant de revenir sur le site macgeneration... Il semblerait que les arguments soient d'abord évalués avant d'être substitués dans le chaîne de caractères. De plus, les arguments qui ne sont pas de simple "getter" semblent être évalués en premier.
> Je dois avouer que ce comportement est plutôt étrange...
> Merci pour ta réponse!
> François




L'ordre d'évaluation des arguments n'est absolument pas garanti en C. Ceci peut varier d'un compilateur a l'autre.

Par contre, l'ordre d'évaluation d'une expression est garanti. Par exemple si tu ecrit
if ( fonction1(a)>0 && fonction2(a)>0)

Tu est sur que fonction1 est invoqué avant fonction2. 

Cordialement


----------



## tatouille (29 Décembre 2007)

Didier Guillion a dit:


> L'ordre d'évaluation des arguments n'est absolument pas garanti en C. Ceci peut varier d'un compilateur a l'autre.
> 
> Par contre, l'ordre d'évaluation d'une expression est garanti. Par exemple si tu ecrit
> if ( fonction1(a)>0 && fonction2(a)>0)
> ...




tient a ce propos, j ai lu un peu de litterature au sujet de ObjC instance variable lookup in class methods


```
@interface Bar : NSObject {
    int sprite;
}
+(id) bar;
@end

@implementation Bar

+(id) bar {
    self = [[Bar alloc] init];
    sprite = 10;
    
    return self;
}
@end
```
tout le monde est d accord cela produira le warning suivant:

warning: instance variable 'sprite' accessed in class method

j ai lu pas mal de truc sur la visibilite, le concept de membre static comme en c++, mais je ne comprend pas le probleme si un warning est genere c est que ce cas peut etre problematique et a ce jours je n ai rien trouve de problematique et alors si c est un probleme d etique objet non plus, si quelqu un a quelques arguments je suis preneur  j ai pas mal bidouille avec la lib objc je les meme modifiee pour jouer, 
si ce warning est purement conceptuel alors que dire de objc version 2 avec @synthesize ou copy/retain une nstring est un objet... c est assez banqual


----------



## tatouille (29 Décembre 2007)

brainois a dit:


> Merci ntx... Effectivement, c'est la conclusion à laquelle je suis arrivée juste avant de revenir sur le site macgeneration... Il semblerait que les arguments soient d'abord évalués avant d'être substitués dans le chaîne de caractères. De plus, les arguments qui ne sont pas de simple "getter" semblent être évalués en premier.
> Je dois avouer que ce comportement est plutôt étrange...
> Merci pour ta réponse!
> François


 non en effet comme le dis didier juste en dessous, il faut savoir qu un printf n est pas "instantané" comme un fprint to stdout,  c est bufferise, de plus si tu utilises objc en mode gc, jouer avec une alloc memoire au milieu du stack c est pas tres conseille, a mon avis tu peux obtenir un beau merdier si tu push au milieu du pool


----------

