[C] Funkcja wycianajaca slowo w tekscie (nie strtok)

0

Witam.
Chce napisac funkje, ktora bedzie dostawala na wejsci TEKST rozdzielony SEPARATORAMI, wskazujemy jej tez argument KTORY mowiacy za ktorym separatorem chcemy wyciac z tekst slowo:

char *wytnij(char **tekst,char separator, int ktory);

np.
TEKST = "jeden||dwa|trzy"
SEPARATOR = '|'
KTORY = 2

Nie moge uzyc funkcji strtok gdyz ona ominie || czyli wtedy gdy miedzy separatorami nie ma nic.
Gdy ktory = 0 to oznacza ze chcemy wyciac slowo przed pierwszym separatorem.
Funkcja w wyniku zwraca wyciete slowo a tekst jest przekazywany przez referencje bo pod nim jest tekst z juz wycietym slowem.

char *wytnij(char **tekst,char separator, int ktory)
{         
     int licznik = 0;     
     char *beg,*end,*wynik,*tmp;     
     beg = &(*tekst[0]);                       
     tmp = (char*)malloc(strlen(*tekst)*sizeof(char));     
     memset(tmp, '\0', strlen(*tekst)*sizeof(char)+1);            
     if(ktory < 0){
              free(tmp);
              printf("ERROR: Please enter number greater that 0.\n");
              return "-1";     
     }
     if(ktory == 0){
        beg=memchr(beg,separator,strlen(*tekst));        
        if (beg == NULL){
           free(tmp);
           printf("ERROR: No delimiters in text.\n");
           return "-1";
        }        
        wynik = (char*)malloc(beg-(*tekst));
        memset(wynik, '\0',beg-(*tekst)+1); 
        memcpy(wynik,*tekst,beg-(*tekst));                
        strcpy(*tekst,tmp);
        free(tmp);                                                               
        return wynik;
     }     
     do{
        beg=memchr(beg,separator,strlen(*tekst));        
        if (beg != NULL && ++licznik==ktory){                             
           end=memchr(++beg,separator,strlen(beg));
           if (end == NULL){
              wynik = (char*)malloc(strlen(beg));
              memset(wynik, '\0',strlen(beg)+1);
              memcpy(wynik,beg,strlen(beg));                                                     
              memmove(tmp,*tekst,beg-(*tekst));
              strcpy(*tekst,tmp);
              free(tmp);                                                                                             
              return wynik;
           }          
           wynik = (char*)malloc(end-beg);           
           memset(wynik, '\0',end-beg+1);         
           memcpy(wynik,beg,end-beg);                                    
           tmp = (char*)malloc(strlen(*tekst)*sizeof(char));                      
           memset(tmp, '\0', strlen(*tekst)*sizeof(char)+1);                     
           memmove(tmp,*tekst,beg-(*tekst)); 
           memmove(tmp+(beg-(*tekst)),end,strlen(end)+1);                            
           strcpy(*tekst,tmp);
           free(tmp);                                                    
           return wynik;           
        }            
     }while(beg++ != NULL);
     if(licznik != ktory){
        free(tmp);             
        printf("ERROR: Too few delimiters in text.\n");
        return "-1";              
     }    
}

Ale jakos mi to nie dziala jak w petli podaje jakis tekst i wywoluje ta funkcje :/ co mzoe byc zle albo mozna zrobic lepiej?

0

O to chodzi?

char* wytnij(char *tekst,char separator,unsigned int ktory)
{
	char* p1=tekst;
	
	while(ktory && *p1)
	{
		++p1;
		if(*p1==separator)--ktory;
	}

	if(ktory || *p1=='\0')return NULL;

	char* p2=p1;
	++p2;
	while(*p2 && *p2!=separator)++p2;

	char* p3=p1;
	if(*p3==separator)++p3;
	size_t cb=(p2-p3);
	char* p4=(char*)malloc(cb+1);
	if(!p4)return NULL;
	strncpy(p4,p3,cb);
	p4[cb]='\0';
	while(*p1++=*p2++);
	return p4;
}
0

Tzn jak odpalam Twoja wersje to mam fatal error ;) I wina chce wysylac raport do Microsoftu :). A czy pod tekstem bedzie zwracany juz ten tekst z wycietym slowem?

Wywala sie na ostanim while:
while(*p1++=*p2++);
Tu masz chyba babola ale poza tym wyglada fajnie :)
Mozesz na to luknac?

0

Funkcja może zwrócić NULL'a, więc sprawdzaj co zwraca.

char text[] = "jeden||dwa|trzy";

printf("%s\n",text);

char* ptr=wytnij(text,'|',2);
if(ptr)
{
    printf("%s\n",ptr);
    free(ptr);
}
printf("%s\n",text);
Michalllll napisał(a)

Wywala sie na ostanim while:
while(*p1++=*p2++);
Tu masz chyba babola ale poza tym wyglada fajnie :)

Tu jest wszystko jak najbardziej OK. Prawdopodobnie podajesz zły wskaźnik w tekst, bo to jedyna część funkcji, która zmienia zawartość bufora.

0
char *wytnij(char *tekst,char separator, int ktory)
{		
	char *sBegin = tekst; // wskazuje bajt za separatorem
	if(!tekst)
		return 0;
	
	for(int i=0;i<ktory;++i)
		if(sBegin = strchr(sBegin,separator))
			++sBegin; // idź krok za separator
		else
			return 0;// za mało separatorów
			
	// znaleziono "ktory" separator:
	int size;
	char sEnd = strchr(sBegin,separator); // znajdź następny separator (kończący)
	if(sEnd)
		size = sEnd - sBegin; // następny separator  istnieje
	else
		size = strlen(sBegin); // brak następnego separatora
	
	char * result = malloc(size+1); // +1 dla końcowego zera
	memcpy(result,sBegin,size);
	result[size]=0; // zero kończące;
	
	return result;
}
0

Wywla sie gdy zrobie tak:

char *text = "jeden||dwa|trzy";//WSKAZNIK zamiast tablicy

printf("%s\n",text);

char* ptr=wytnij(text,'|',2);
if(ptr)
{
    printf("%s\n",ptr);
    free(ptr);
}
printf("%s\n",text);

Blad jest tez gdy wywolam tak :

char text[] = "jeden||dwa|trzy";

printf("%s\n",text);

char* ptr=wytnij(text,'|',1);
if(ptr)
{
    printf("%s\n",ptr);
    free(ptr);
}
printf("%s\n",text);

Wtedy wynik to:

jeden||dwa|trzy

jeden|dwa|trzy

A chcialbym zeby bylo

jeden||dwa|trzy

jeden||dwa|trzy

Dasz rade cos z tym zrobic?

0

Wywla sie gdy zrobie tak:

char *text = "jeden||dwa|trzy";//WSKAZNIK zamiast tablicy

Stringów w takiej formie ta funkcja przyjmować nie może.

Blad jest tez gdy wywolam tak :

char text[] = "jeden||dwa|trzy";

[...]

To nie błąd, tylko tak to zostało napisane - za mało szczegółów, więc przyjąłem, że separator też idzie w !@#$% ;)

[...]

while(ktory && *p1)
{
     if(*p1++==separator)--ktory;
}

[...]

char* p2=p1;
while(*p2 && *p2!=separator)++p2;

size_t cb=(p2-p1);
char* p4=(char*)malloc(cb+1);
if(!p4)return NULL;
strncpy(p4,p1,cb);

[...]
0

SUPER :) Jestes wielki.
Mam jeszcze jedna prosbe. Moze bedziesz mial chwilke rzucic okiem jeszcze na ta funkcje:

Ma ona za zadanie wstawiac cos do tekstu (podobnie jak poprzednio rozdzielonym separatorami):

bufferIn to tekst wejsciowy
bufferOut to tekst z juz wstawionym slowem
separator jak poprzednio
za_ktorym j/w
wstawic slowo do wstawienia

Moze uda Ci sie ja jakos podrasowac cos na ksztalt wytnij? Bylbym bardzo wdzieczny.

int wstaw3(char *bufferIn, char** bufferOut, char separator, int za_ktorym, char wstawic[])
{ 
  char * pch;
  int licznik = 0;  
  *bufferOut = (char*)malloc(strlen(bufferIn)+strlen(wstawic)+1*sizeof(char)); 
  if (*bufferOut==NULL) printf("ERROR with memory allocation in wstaw3()"); 
  memset(*bufferOut,'\0',strlen(bufferIn)+strlen(wstawic)+1); 
  pch = &(bufferIn)[0];
  if (pch==NULL) return -1;  
  if (za_ktorym == 0) {
     memcpy(*bufferOut,wstawic,strlen(wstawic));     
     strcat(*bufferOut,bufferIn);        
     return 0;
  }     
  do{          	
    pch=memchr(pch,separator,strlen(bufferIn));   
    if(pch != NULL && ++licznik == za_ktorym )   
    {                
      memcpy(*bufferOut,bufferIn,pch-bufferIn+1);
      memcpy(*bufferOut+(pch-bufferIn+1), wstawic, strlen(wstawic));
      memcpy(*bufferOut+(pch-bufferIn+1)+strlen(wstawic), bufferIn + (pch-bufferIn+1), strlen(bufferIn) - (pch-bufferIn));                
      return 0;           
    }		
  }while( pch++ != NULL );
  if(licznik != za_ktorym){
             memcpy(*bufferOut,bufferIn,strlen(bufferIn)); 
             return 0;
  }
  return 0;
}
0

Masz szczęście, że mam słabość do takich drobnych rzeczy ;-)

char* wstaw3(const char *bufferIn, char separator,unsigned int za_ktorym, const char *wstawic)
{
	const char* p1=bufferIn;

	while(za_ktorym && *p1)
	{
		if(*p1++==separator)--za_ktorym;
	}

	if(za_ktorym || *p1=='\0')return NULL;

	const char* p2=p1;
	while(*p2 && *p2!=separator)++p2;

	size_t cb1=strlen(bufferIn);
	size_t cb2=strlen(wstawic);
	size_t cb3=(p2-p1);

	char* p3=(char*)malloc(cb1+cb2-cb3+1);
	if(!p3)return NULL;

	char* p4=p3;
	while(bufferIn!=p1 && (*p4++=*bufferIn++));
	while(*p4=*wstawic++)++p4;
	while(*p4++=*p2++);
	return p3;
}
0

Zarejestrowalem sie wreszcie :)

Funkcja dziala i jest ok ale jakbym mogl prosic o poprawke tak zeby zwracala nie nowy tekst tylko 0 dla sukcesu i -1 dla bledu a przerobiony tekst byl pod bufferIn (tzn tak jakby go przekazywac przez referencje)
cos a la:

char text[] = "jeden||dwa|trzy|cztery||piec";
char wstawiane[] = "WSTAWIONE";

printf("%s\n",text);

int ptr=wstaw3(text,'|',1,wstawiane);
printf("%d\n",ptr);   

printf("%s\n",text);

da cos takiego:

jeden||dwa|trzy|cztery||piec
0
jeden|WSTAWIONE|dwa|trzy|cztery||piec

lub dla bledu:

jeden||dwa|trzy|cztery||piec
-1
jeden||dwa|trzy|cztery||piec
0

Tyle to już chyba sam możesz zrobić :>

0

No wlasnie jestem w trakcje probowania :) Jak na razie udalo mi sie przerobic wytnij na o prostu kopiuj :) Kurcze nie radze sobie dorze z roznica miedzu char* a char[]. Wiec dlatego prsze o pomoc.

Kurcze no nie daje rady. Domyslam sie ze to ma byc cos w stylu wytnij ale nie moge zrozumiec tych wszysktich wskaznikow przez Ciebie tam uzytych :/ Jak masz chwile to prosze jeszcze o pomoc.

0

Kurcze nie radze sobie dorze z roznica miedzu char* a char[].

Sprawa jest prosta. Taka deklaracja:

char wstawiane[] = "WSTAWIONE";

tworzy tablicę tyle, że jej rozmiar oblicza kompilator na podst. długości stringa. Ekwiwalent tego zapisu to:

char wstawiane[10];
strcpy(wstawiane,"WSTAWIONE");

Z kolei taka deklaracja:

char* wstawiane = "WSTAWIONE";

tworzy wskaźnik do stringa, który jest tylko do odczytu, więc nie możesz zmieniać jego (stringa) zawartości. Wersja poprawna powinna wyglądać tak:

const char* wstawiane = "WSTAWIONE";
int wstaw3(char **bufferIn, char separator,unsigned int za_ktorym, const char *wstawic)
{
	char* p1=*bufferIn;

	[...]	
	
	size_t cb1=strlen(*bufferIn);
	
	[...]	
	
	while(*bufferIn!=p1 && (*p4++=*(*bufferIn)++));

	[...]	
	
	*bufferIn=p3;
	
	[...]
}

returny sobie sam pozmieniaj ;)

[...] nie moge zrozumiec tych wszysktich wskaznikow przez Ciebie tam uzytych

Wrzuć na debugger i zobacz jak to wszystko działa.

0

Wielkie dzieki.
Tak wlasnie kombinowalem.

Jeszcze raz wielkie dzieki za cala pomoc :)

Pisze dosc duzy projekt wiec jakby co to bede sie odzywal :)
Pozdrawiam

0

a czy moglbys mi powiedziec jeszcze jak uzywac tych funkcji tak zeby nie zapelnialo pamieci?
bo uzywam ich w petli i to bardzo czesto i w pewnym momenci program sie przerywa nie wiadomo dlaczego.
Wywoluje je tak:

char * linia;
char * linia_do_wyciecia;
char *tmp;

tmp = wytnij(linia_do_wyciecia,'|',5);
linia = wstaw(linia,'|',5,tmp);
linia = wstaw(linia,'|',5,tmp);
linia = wstaw(linia,'|',5,tmp);
linia = wstaw(linia,'|',5,tmp);

Czy powinienem gdzies robic free()? I czy moge robic cos takiego bezpiecznie?

linia = wstaw(linia,'|',5,tmp);
0

Czy powinienem gdzies robic free()?

Tak. wytnij zwraca "nową pamięć" lub NULL. To samo ze wstaw.

I czy moge robic cos takiego bezpiecznie?
[...]

To zależy. linia i tmp nie mogą być NULL. Jeżeli oba parametry są wynikiem działania którejś z wcześniej omawianych funkcji, to może pojawić się NULL, więc trzeba uważać. Inna sprawa, że jeżeli linia jest pamięcią do zwolnienia, to taki zapis będzie powodował wyciek.

Tak to powinno wyglądać:

char* ptr = wstaw(linia,'|',5,tmp);
if(ptr)
{
	free(linia);
	linia=ptr;
}
0

to mam taki problem ze wstaw

int wstaw31(char **bufferIn, char separator,unsigned int za_ktorym, const char *wstawic)
{                  
        char* p1=*bufferIn;       

        while(za_ktorym && *p1)
        {
                if(*p1++==separator)--za_ktorym;
        }

        if(za_ktorym || *p1=='\0')return -1;

        const char* p2=p1;
        while(*p2 && *p2!=separator)++p2;

        size_t cb1=strlen(*bufferIn);
        size_t cb2=strlen(wstawic);
        size_t cb3=(p2-p1);

        <b>char* p3=(char*)malloc(cb1+cb2-cb3+1);</b>
        if(!p3)return -1;

        char* p4=p3;
        while(*bufferIn!=p1 && (*p4++=*(*bufferIn)++));
        while(*p4=*wstawic++)++p4;
        while(*p4++=*p2++);        
        
        *bufferIn=p3;                   
        return 0;
}

bo am w sobie potencjalnego leak'a. Robi malloca a nigdzie tego nie zwalnia. :/

0

No to robisz analogicznie jak wyżej to pokazałem ;) Nieco więcej inwencji własnej...

1 użytkowników online, w tym zalogowanych: 0, gości: 1