Objective-C: Casse-tête Malloc

brainois

Membre confirmé
10 Août 2006
63
7
48
Bruxelles, Belgique
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:
Bloc de code:
./Fraction 3/4 1/3
Je m'attends à recevoir le résultat suivant:
Bloc de code:
3/4
1/3
The value of 3/4 + 1/3 is 1.08333
Mais j'obtiens:
Bloc de code:
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:
Bloc de code:
#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:
Bloc de code:
#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
Bloc de code:
#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;
}
 
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
 
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
 
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.
 
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
 
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
 
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


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

Bloc de code:
@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 :zen: 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
 
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