OVH Cloud OVH Cloud

strsub

31 réponses
Avatar
Jean Pierre Daviau
Bonjour à tous,

N'ayant pu trouver une fonction du genre sur google...

La fonction imprime null

/* strsub.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char * strsub(char *, int);

char * strsub(char * source, int end){

char *dest = (char*)malloc(strlen(source)+1);
char *tmp = source + end;
strcpy(dest, "a");

if(strlen(source)<255 && strlen(source) > (unsigned)source +
end){

while(source++ < tmp){
*dest++ = *source;
}
dest = '\0';
return dest;
}else{
return "Chaîne de plus de 255 lettres ou indice de fin trop
grand.";
}
}

int main(void)
{
char *chaine = "Chaîne de plus de 255 lettres.";

printf("--%s--\n", strsub(chaine + 4, 8));
return 0;
}


--
Merci

Jean Pierre Daviau
--
windows Xp
asus p4 s533/333/133
Intel(R) Celeron (R) CPU 2.00 GHz
Processor Radeon7000 0x5159 agp

10 réponses

1 2 3 4
Avatar
j4e8a16n
On Jan 30, 10:04 am, "Antoine Leca" wrote:
Ennews:ljInj.32247$, Jean Pierre Daviau va
escriure:

Oui, mais ma fonction peut copier une sous-chaîne située
n'importe où dans une chaîne ...
chaine


ch
aine
in
hai
ne

Il faut savoir où ça commence et où ça finit.Nn?

Ce n'est pas une caractéristique probante. En C, une sous-chaîne qui
commence au n-ième caractère d'une chaîne s, cela s'écrit
    s+n
toujours, partout, et sans se compliquer la vie à passer un argument
complémentaire.



Avatar
Jean Pierre Daviau
/* insertout.c */
/*
* Retourne une section de chaîne.
* unsigned int fin doit être <= que longueur de chaîne - 1
* strsub(char * chaine, unsigned int début, unsigned int fin)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define message "Indice de trop grand."
char * strsub(char *, unsigned int, unsigned int);


char *
strsub(char * source, unsigned int start, unsigned int end){

size_t l_en = strlen(source);
/* adresses alloué dans la chaîne */
char * debut = source + start;
char * fin_source = source + l_en;
char * fin_sous_chaine = source + start + end;

/* adresses alloué ailleurs */
char *dest = (char*)malloc(l_en +1);
/*
* dest point*ait* vers une zone de mémoire allouée
dynamiquement, et cette
* valeur n'est jamais sauvegardée, on va droit vers un problème
de fuite mémoire...
*/
char *destInt = dest;

//printf("%d %d %p %pn", end, l_en, &dest, &fin);

if (destInt == NULL) {
fprintf(stderr, "Problème d'allocation mémoiren");
return NULL;
}

/* Vérifions si les adresses sont à l'intérieur des adresses de
la chaîne. */
if(fin_sous_chaine <= fin_source){
while(debut++ < fin_sous_chaine)
*dest++ = *debut;

*dest = '';
return destInt;
}

return message;
}

int main(void)
{
char *chaine = "Chaîne de lettres.";

printf("->%s<-n", strsub(chaine, 6, 10));
return 0;
}
/* insertout.c */
Avatar
Aris

char *dest = (char*)malloc(l_en +1);


Attention c'est à proscrire absolument !
si on a oublié d'inclure le header pour malloc, malloc renvera
implicitement un int qui sera converti silencieusement en pointeur. Sur
certaines architectures (amd64 par ex) ces types n'ont pas la même taille.
Il vaut mieux laisser le compilateur se charger du transtypage
implicite, surtout quand on passe d'un void * à un char *

Avatar
Michel Decima
/* insertout.c */
/*
* Retourne une section de chaîne.
* unsigned int fin doit être <= que longueur de chaîne - 1
* strsub(char * chaine, unsigned int début, unsigned int fin)
*/


Pourquoi une precondition sur _fin_ alors qu'il n'y en a pas
sur _debut_ ? ( et ce n'est pas teste dans le code...)
Il faudrait aussi exiger (controler) _debut_ <= _fin_ , non ?

AMHA, l'interface serait plus agreable si on donnait la position
de debut et la taille, plutot que debut et fin, avec troncature
automatique si la taille demandee est plus grande que disponible
( strlen(chaine+debut) )...

Avatar
Erwan David
Aris écrivait :

Attention c'est à proscrire absolument !
si on a oublié d'inclure le header pour malloc, malloc renvera
implicitement un int qui sera converti silencieusement en
pointeur. Sur certaines architectures (amd64 par ex) ces types n'ont
pas la même taille.


Oui, mais ça permet à ceux qui bossent sur des architectures à entiers
16 bits et pointeurs 32 bits de se marrer...


--
Le travail n'est pas une bonne chose. Si ça l'était,
les riches l'auraient accaparé

Avatar
Antoine Leca
En news:47a1ef8e$0$32003$,
Aris va escriure:

char *dest = (char*)malloc(l_en +1);


Attention c'est à proscrire absolument !


Ce qui devrait être proscrit, ce sont les implémentations qui fournissent un
entête <stdlib.h> où malloc() n'est pas déclaré (ou qui ne signale pas
d'erreur pour un entête inconnu).


si on a oublié d'inclure le header pour malloc,


Avec des si...

En l'occurence, une solution serait de déclarer explicitement malloc(), ce
qui est possible si on a #inclus <stdio.h>, ou <time.h>, ou <string.h>, ou
<wchar.h> etc.

Une autre « solution », qui marche très souvent voire presque toujours même
si formellement c'est incorrect, est de déclarer explicitement en style
ancien (K&R), avec
char *malloc();

Cependant cela va poser problème quand on va (enfin) #inclure l'entête.

Bref, avec des si, on peut remplir Usenet...


Antoine


Avatar
Antoine Leca
En news:oykoj.9$, Jean Pierre Daviau va escriure:
* Retourne une section de chaîne.
* unsigned int fin doit être <= que longueur de chaîne - 1
* strsub(char * chaine, unsigned int début, unsigned int fin)


#include <string.h>
#include <stdlib.h>
#include "strlcpy.h"
/*size_t strlcpy(char *dst, const char *src, size_t siz);*/

char* strsub(const char chaîne[], unsigned début, unsigned fin)
{
size_t alloué;
char *r;
if( début>strlen(chaîne)
|| fin<début
|| !(r = malloc(alloué = fin-début+1)) )
return NULL;
strlcpy(r, chaîne+début, alloué);
return r;
}


S'il vous manque strlcpy sur votre machine,
ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/strlcpy.c
(et récupérez donc en même temps
ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/strlcat.c, et jettez
donc un ½il distrait à l'indicatif utilisateur de la dernière personne ayant
modifié ce source... ;-) )


Antoine

Avatar
j4e8a16n
On Jan 31, 11:09 am, Michel Decima
wrote:

/* insertout.c  */
/*
 * Retourne une section de chaîne.
 * unsigned int fin  doit être <= que longueur de chaîne - 1
 * strsub(char * chaine, unsigned int début,  unsigned int fin)
 */


Pourquoi une precondition sur _fin_ alors qu'il n'y en a pas
sur _debut_ ? ( et ce n'est pas teste dans le code...)
Il faudrait aussi exiger (controler) _debut_ <= _fin_ , non ?

AMHA, l'interface serait plus agreable si on donnait la position
de debut et la taille, plutot que debut et fin, avec troncature
automatique si la taille demandee est plus grande que disponible
( strlen(chaine+debut) )...


Il faudrait que unsigned int start soit négatif pour qu'il y ait
problème. Pourquoi quelqu'un voudrait-il une sous chaîne qui commence
avant la chaîne qu'il veut diviser?


Avatar
Michel Decima

* Retourne une section de chaîne.
* unsigned int fin doit être <= que longueur de chaîne - 1
* strsub(char * chaine, unsigned int début, unsigned int fin)
*/
Pourquoi une precondition sur _fin_ alors qu'il n'y en a pas

sur _debut_ ? ( et ce n'est pas teste dans le code...)
Il faudrait aussi exiger (controler) _debut_ <= _fin_ , non ?

AMHA, l'interface serait plus agreable si on donnait la position
de debut et la taille, plutot que debut et fin, avec troncature
automatique si la taille demandee est plus grande que disponible
( strlen(chaine+debut) )...


Il faudrait que unsigned int start soit négatif pour qu'il y ait
problème. Pourquoi quelqu'un voudrait-il une sous chaîne qui commence
avant la chaîne qu'il veut diviser?


Pourquoi negatif ? Si start est plus grand que la taille de la chaine,
genre start = strlen(chaine)+1, ca devrait suffire, non ? (je viens
de m'apercevoir que j'avais ecrit _debut_ a la place de _start_ ...)

Dans la version de Jean-Pierre, il n'y a aucun test evident dans
les premieres ligne de la fonction, et s'il n'y a pas de probleme
sur les indices, c'est uniquement grace a une construction obscure
vers la fin.
Si cette fonction echoue pour un probleme d'allocation, je recevrais
NULL, c'est pas fait pour surprendre. Par contre, si elle echoue pour
un probleme d'indice, je recois qd meme une chaine "Indice trop grand",
et j'ai un doute serieux sur ce qui va se passer lors du free()...

Dans la version proposee par Antoine, on voit immediatement et tres
clairement ce qui se passe lorsque les preconditions ne sont pas
verifiees, et il y a bien les tests sur les indices que j'attendais
(et si fin est superieur a la taille de la chaine, on tronque a
strlen(chaine))
Et aussi, on sait quoi faire du resultat: si la fonction echoue,
j'obtiens NULL, sinon je recois de la memoire dynamique que je
dois desallouer.

Apres, on peut considerer le probleme de 'unsigned fin', qui est
une position et pas une longueur. Si c'etait une longueur, il n'y aurait
aucune ambiguite, mais comme c'est une position, il faudrait preciser
si elle est comprise dans l'intervalle ou non... et visiblement Antoine
et Jean-Pierre ne sont pas du meme avis :

int main(void)
{
char text[] = "text" ;
char* s ;
printf("'%s'n", ((s = strsub(text, 0, 0)) ? s : "NULL" ));
printf("'%s'n", ((s = strsub(text, 0, 1)) ? s : "NULL" ));
printf("'%s'n", ((s = strsub(text, 1, 1)) ? s : "NULL" ));
printf("'%s'n", ((s = strsub(text, 1, 2)) ? s : "NULL" ));
}

Les sorties sont legerement differentes:

'' ''
'e' 't'
'x' ''
'xt' 'e'

MD.



Avatar
Vincent Lefevre
Dans l'article <47a1fe23$0$12987$,
Antoine Leca écrit:

#include <string.h>
#include <stdlib.h>
#include "strlcpy.h"
/*size_t strlcpy(char *dst, const char *src, size_t siz);*/

char* strsub(const char chaîne[], unsigned début, unsigned fin)
{
size_t alloué;
char *r;
if( début>strlen(chaîne)
|| fin<début
|| !(r = malloc(alloué = fin-début+1)) )
return NULL;
strlcpy(r, chaîne+début, alloué);
return r;
}



S'il vous manque strlcpy sur votre machine,
ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/strlcpy.c
(et récupérez donc en même temps
ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/strlcat.c, et jettez
donc un oeil distrait à l'indicatif utilisateur de la dernière personne ayant
modifié ce source... ;-) )


Et récupérez un compilateur qui reconnaisse les caractères accentués. :)

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)

1 2 3 4