Eviter les debordement memoire en c

Signaler
Messages postés
45
Date d'inscription
samedi 5 juin 2004
Statut
Membre
Dernière intervention
16 mars 2009
-
Messages postés
3212
Date d'inscription
lundi 7 novembre 2005
Statut
Membre
Dernière intervention
16 février 2009
-
bonjour tout le monde j'ai un probleme avec la gestion des pointeurs voila je m'explique de suite...
j'ai une fonction "ExtractString" dont voici l'entete :
char *ExtractString(char *string,int pos,char sep);cette fonction extrait une sous chaine de l'argument "string".le remplisage du pointeur renvoyer par la fonction commence a partir de l'argument pos et continue tant que le caractere lu est different de l'argument sep!
mais voila la sous chaine renvoyee ne prend que 32 caracteres!alors comment empecher le debordement memoire durant le remplisage du pointeur!
gespere m'etre bien expliquer
merci..

11 réponses

Messages postés
653
Date d'inscription
mardi 6 décembre 2005
Statut
Membre
Dernière intervention
10 novembre 2014
2
Une string est normalement toujours terminer par le caractere NULL(0), tu as donc juste a controle que le caractere pointé par ton pointeur est positif..
Poste ton code sinon ce sera mieux pour t'aider

Neo_Fr
Messages postés
45
Date d'inscription
samedi 5 juin 2004
Statut
Membre
Dernière intervention
16 mars 2009

le voici :

void extractstring(char *string,int pos,char sep)
{
     char *extract = malloc(32*sizeof(char));
    int i;i=0;
  char c = string[i];
while(c!=sep)
{
  extract[i] = sep;
}
}
Messages postés
45
Date d'inscription
samedi 5 juin 2004
Statut
Membre
Dernière intervention
16 mars 2009

mince g fait kelke erreur dsl :
dans le while :
extract[i] = c;//et non sep
i++;
c = string[i];
et si vous pouver m'aider dans l'ecriture avec les pointeur d'une facon plus efficace merci..et dsl encore
Messages postés
653
Date d'inscription
mardi 6 décembre 2005
Statut
Membre
Dernière intervention
10 novembre 2014
2
Evite tant que possible de retourner de la memoire allouer avec malloc si tu veux pas etre obliger de faire des free() partout dans ton code.., le mieux reste d'écrire directement sur un pointeur passer en param de cette facon tu fait l'alloc/desalloc en dehors de ta fonction ce qui evite tout oublie de desalloc..

Ex:

void __stdcall ExtractString(LPSTR lpszIn, LPSTR lpszOut, DWORD dwStartFrom, char Separator)
{
LPSTR lptr;
lptr = lpszIn + dwStartFrom;
while(*lptr !Separator) *lpszOut++ *lptr++;
*lpszOut = 0;
}

int main(void)
{
char szTest[] = "blablablaCeci est un test;blabla";
char szRet[16];
ExtractString(szTest, szRet, 9, ';');
printf("%s", szRet);

system("PAUSE");
return 0;
}

Neo_Fr
Messages postés
3212
Date d'inscription
lundi 7 novembre 2005
Statut
Membre
Dernière intervention
16 février 2009
16
void ExtractString(LPSTR lpszIn, LPSTR lpszOut,, UINT uLen, UINT uStartFrom, char cSeparator)

{

    LPSTR lptr;

    // Ici on pourrait tester que les paramètres contiennent les valeurs nécessaires

    lptr = lpszIn + uStartFrom;    while(*lptr && --uLen && *lptr !cSeparator) *lpszOut++ *lptr++;
    *lpszOut = 0;

}

ExtractString(szTest, szRet, sizeof(szRet), 9, ';');

C++ (@++)<!--
Messages postés
98
Date d'inscription
vendredi 17 février 2006
Statut
Membre
Dernière intervention
24 janvier 2018

Salut, je te propose ce code que je n'ai pas testé
2 inconvénients:
- dans notre cas nous n'avons alloué que 32 octets(soit 32 caractères au maximum).
- si l'arguments "sep" n'est pas trouvé, je ne veux même pas savoir ce qui va se passer car ile while n'a aucune autre clause d'arret.

void extractstring(char *string,int pos,char sep)
{
char *extract = malloc(32*sizeof(char));
int i;


i= 0;
j = pos;


while( extract[i] != sep )


extract[i] = string[j];


i++;
j++;


}


extract[i] = '\0';
}
PS: je crois que "char *extract malloc(32*sizeof(char));" pourrait être remplacé par "char *extract malloc(strlen(string)*sizeof(char)); "
Messages postés
3212
Date d'inscription
lundi 7 novembre 2005
Statut
Membre
Dernière intervention
16 février 2009
16
"- dans notre cas nous n'avons alloué que 32 octets(soit 32 caractères au maximum)."

Là tout l'intérêt du code proposé par neo_fr

"- si l'arguments "sep" n'est pas trouvé, je ne veux même pas savoir ce
qui va se passer car ile while n'a aucune autre clause d'arret."

Là tout l'intérêt du code modifié de neo_fr que j'ai proposé.

C++ (@++)<!--
Messages postés
46
Date d'inscription
vendredi 31 octobre 2003
Statut
Membre
Dernière intervention
7 août 2008

Pour revenir à la question de l'allocation dynamique, même si pour ce type de fonction il est clair qu'un alloc interne n'est pas la meilleure solution, je donnerais ça pour la posterité et la pédagogie pour les cas où c'est nécessaire :

char * extractString(char * str, size_t pos, char sep) {

    int i;
    char * ext;

    if (pos > strlen(str))
       return NULL;

    /* Rappel au passage qu'un pointeur est passé par valeur */
    str += pos;

    for ( i = 0; i < strlen(str) && str[i] != sep;i++);

    /* Connaissant désormais la taille à allouer on ne risque plus l'overflow */
    ext = malloc(i+1);
    memcpy(ext,str,i);
    ext[i] = 0;

    return ext;

}

int main() {

    char str [] = "da;test;string", * tmp;
   
    if ((tmp = extractString(str,3,';')) != NULL)
        printf("%s\n",tmp);
   
    free(tmp);
   
    return 0;

}

Une autre solution, come cité plus haut serait de systématiquement allouer la taille de la chaine originale, mais dans ce cas l'utilité d'une allocation dynamique devient nulle.
Messages postés
3212
Date d'inscription
lundi 7 novembre 2005
Statut
Membre
Dernière intervention
16 février 2009
16
Appel strlen UNE SEULE FOIS avant le test if(pos > strlen(...)). D'ailleurs ici, ça devrait être if(pos >= len).
Puisque que la taille est déjà récupérée, on l'utilisera aussi dans la boucle mais sinon, suffit simplement de tester si le caractère courant (str[i]) est non nul.

"mais dans ce cas l'utilité d'une allocation dynamique devient nulle."

Peut-être mais pour la perte de cycle CPU que cela occasionne, peut-être est-il mieux de ne pas en tenir compte.

C++ (@++)<!--
Messages postés
46
Date d'inscription
vendredi 31 octobre 2003
Statut
Membre
Dernière intervention
7 août 2008

Tout d'abord, les "oprimisations" du type n'appeller une fonction constante qu'une fois ont rarement un effet positif. Voire des effets négatifs. Pourquoi ? Parce qu'il est incroyable de voir ce que le compilateur fait dans notre dos. Notamment, ce genre de chose est transformée en un seul appel dont la valeur est stockée dans un registre (pas forcément le cas d'une variable déclarée explicitement). Ca dépend des compilateurs, des plateformes, à tel point que ça ne vaut pas la peine d'en parler.

Si on veut chipoter, je dirais qu'un str[i] impose un defer du pointeur et prends un cycle d'horloge de plus qu'une comparaison avec un entier.

Enfin, et *surtout* j'ai écrit rapidement ce bout de code pour permettre à l'auteur du topic d'avoir un exemple d'utilisation de pointeurs et de l'allocation dynamique, sans prétendre qu'il était meilleur ou optimisé. J'ai d'ailleurs précisé que ce n'était pas la meilleure solution. Ceci dit, pour la compréhension il est bon de pouvoir connaitre une ou deux manières de faire. Je rappelle d'ailleurs que beaucoup de librairies ou d'interfaces (SQLite, OpenSSL, ...) utilisent couramment ce genre de techniques.

Quoiqu'il en soit, j'avoue que je passe par ce site assez rarement. Quand je vois un message auquel je peux répondre rapidement et simplement je le fais. Si c'est pour me coltiner des réponses négatives et qui réduisent ma contribution à deux points lambda qui n'ont pas de rapport avec le sujet alors que j'essaie d'apporter un tout petit peut de pédagogie, merci bien...

Cordialement,
Messages postés
3212
Date d'inscription
lundi 7 novembre 2005
Statut
Membre
Dernière intervention
16 février 2009
16
"Parce qu'il est incroyable de voir ce que le compilateur fait dans
notre dos. Notamment, ce genre de chose est transformée en un seul
appel dont la valeur est stockée dans un registre (pas forcément le cas
d'une variable déclarée explicitement)."

Pas du tout. La valeur déclaré explicitement a toutes les chances d'être placée directement dans un registre. Un appel à une fonction de ce genre est trop incertain. En effet, rien ne garanti au compilo que la chaine ne sera pas modifiée dans la boucle (explicitement ou avec une fonction). Pour cette raison, un appel à une fonction reste un appel à une fonction ("inliné" dans certains cas mais dont le code est toujours présent.) et doit être considéré ainsi dans le code source aussi.

char buf[300];
int i;

fgets(buf, sizeof(buf), stdin);

for(i = 0; i < strlen(buf); i++)
    printf("%c", buf[i]);

Génère donc un listing de ce code et jette un coup d'oeil au code assembler (optimiser par le compilo bien entendu). Tu me reparleras de tes supposées optimisations automatiques après.

Je remarque une chose bien précis (code généré avec VC++):

$LL9@main:
    mov cl, BYTE PTR [eax]
    inc eax
    test   cl, cl
    jne SHORT $LL9@main

C'est le strlen "inliné".
Et ce code est tout en bas de la boucle et reviendra donc forcément à chaque tour de boucle.

"Si c'est pour me coltiner des réponses négatives et qui réduisent ma
contribution à deux points lambda qui n'ont pas de rapport avec le
sujet alors que j'essaie d'apporter un tout petit peut de pédagogie,
merci bien..."

Je n'essaie pas de réduire pas tes efforts à zéro. J'essaie de les corriger au mieux de mon savoir.
N'oublie pas que les débutants on tendance à tout copier sans se posé de question.

C++ (@++)<!--