Usuwanie znakow z konca lancucha znakow

0

Potrzebuje funkcji usuwajacej znaki z początku i konca istniejacego lancucha znakow. Moja funkcja usuwajaca dane znaki z początku stringa dziala dobrze - po prostu przesuwam wskaznik do przodu.

Zalezy mi na tym, aby funkcja usuwajaca znaki z konca lancucha operowala na danych istniejacych juz w pamieci, w miare mozliwosci nie alokowala i nie zwracala wskaznika do nowego lancucha. Mysle i nie idzie mi to. Bede wdzieczny za wskazowki.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

void begindelchar(char** str, const char ch)
{
  while(**str)
    if(**str == ch) ++(*str);
    else return;
}

void enddelchar(char** str, const char ch)
{
  int len = strlen(*str);
  char* ptr = *str + len;
  
  for(int i = len; i > 0; --i) {
    if(*ptr == ch) {
      *ptr = 0;
      --ptr;
    } else return;
  }
}

int main()
{   
  char* line = NULL; size_t size;
  int length;
    
  char* test = "   BlablablABLA!  ";
  printf("len: %d\n", strlen(test));
  enddelchar(&test, ' ');
  printf("%d %s\n", strlen(test), test);
}
0

To Twoje usuwanie z przodu to jakiś koszmarek ;). Wprawdzie nie przy tym co się dzieje w main, ale pewnie później doprowadzi do wycieków pamięci. Poczytaj o c-stringach i pamiętaj, że literały są const (chyba, że się mylę).

Usuwanie z przodu: przesuwanie wszystkiego co ma nie zostać usunięte w lewo o tyle miejsc ile znaków usuwasz.
Usuwanie z tyłu: wstawienie w miejsce pierwszego usuwanego znaku(patrząc od początku) NULL

0
  1. Usuwanie z końca łańcucha jest dobre, tylko czytasz o jeden znak za daleko. Ponadto niepotrzebny jest tu wskaźnik na wskaźnik, bo nie zmieniasz wartości wskaźnika:
void enddelchar(char* str, const char ch)
{
  int len = strlen(str);
  char* ptr = str + (len-1); // str+len wskazuje na znak "za ostatnim", czyli null terminator; musimy wziac znak wczesniejszy
 
  while (*ptr == ch)
    *ptr-- = '\0';
}
  1. Usuwanie z początku nie jest prawidłowe; nie powinieneś tak bezczelnie przesuwać wskaźnika. Zauważ, że wskaźnik pokazuje na początek zaalokowanego bloku. Jeśli go zmienisz, stracisz adres początku bloku i nie będziesz mógł go zwolnić. Prawidłowym rozwiązaniem jest policzenie, ile znaków z początku należy usunąć, a następnie przesunąć resztę łańcucha, czyli:
void begindelchar(char* str, const char ch)
{
  int k = 0;
  char* ptr = str;
  while (*ptr++ == ch)
    ++k;
  int len = strlen(str);
  for (int i = 0; i + k <= len; ++i) // lecimy do str[len], bo to jest null terminator, jego tez trzeba przeniesc
    str[i] = str[i+k];
}
0

Dzięki za zwrócenie uwagi, przecież jak tak trwale zmodyfikuje wskaźnik to może być problem z przywróceniem pamięci. Zapomniałem, że tu nie ma garbage collectora co się o wszystko martwi. Będę próbował zaimplementować funkcje działające w miejscu na sposób jaki podałeś przez przesuwanie.

A przy okazji chciałbym pokazać inne również raczej potworki, ale działające z użyciem kopiowania. Nie bardzo mi się podoba to podejście, ale się dopiero uczę. Czy jest ono kompletnie do niczego, jeśli nie co ewentualnie warto poprawić.

Pozdrawiam,

char* begindelchar(const char* str, const char ch)
{
  int bytes = strlen(str);
  char* new = NULL;
  
  if( (new = (char*) malloc(bytes + 1)) == NULL) {
    fprintf(stderr, "Malloc error!\n");
    return NULL;
  }
  char* nptr = new;
  bool begin = true;
  while(*str) {
    if(! (*str == ch && begin == true) ) {
      begin = false;
      *nptr = *str;
      ++nptr;
    }
    ++str;
  }
  
  int len = strlen(new);
  if(len < bytes)
    new = (char*) realloc(new, len + 1);
 
  return new;
}


void reverse(char *str)
{
  int len = strlen(str);
  int half = len / 2;
  for (int i = 0 ; i < half; ++i)
  {
     char c = str[i];
     str[i] = str[len-i-1];
     str[len-i-1] = c;
  }
}

char* enddelchar(const char* str, const char ch)
{
  int bytes = strlen(str);
  char* new = NULL;
  
  if ( (new = (char*) malloc(bytes + 1)) == NULL ) {
    fprintf(stderr, "Malloc error!\n");
    return NULL;
  }
  
  char* nptr = new;
  char* cptr = (char*) str + bytes - 1;
  bool end= true;
  
  while(*str) {
    if(! (*cptr == ch && end == true) ) {
      end = false;
      *nptr = *cptr;
      ++nptr;
    }
    ++str; --cptr;
  }
  reverse(new);
  
  int len = strlen(new);
  if(len < bytes)
    new = (char*) realloc(new, len + 1);
  
  return new;
}

0

reverse można zapisać inaczej

int reverse(char * a, char * b){
        return a < b;}

a woła się to tak:

        qsort(s, strlen(s), 1, reverse);

albo tylko fragment qsort(s+5, 8, 1, reverse)odrzucamy k końcowych znaków, pozostawiamy p XXXXPPPPKKKK

        s[strlen(s)-k]=0;
        qsort(s, strlen(s)+1, 1, reverse);
        qsort(s, p+1, 1, reverse);

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