Wskaźniki w C do stringów...

0

Jest sobie pewien kod w C:

#include <stdio.h>

char * LineToStr(char *in_s, int in_l, char * separator){

  char *s = in_s;
  int i;
  char *a,*b;

  /* usuwam segmenty niepotrzebne przed */
  for (i=2;i<=in_l;i++){
    if (s=strstr(s,separator)) s++;
  }

  /* usuwam segmenty niepotrzebne po */
  if (a=strstr(s,separator)){
    a++;
    a="\0";
    //memcpy(&s[1],"\0",1);

//    printf("Wskaźnik a=%s\n",a);
  }


  return s;
}

void main(){
  printf("tekst=%s\n",LineToStr("jeden;dwa;trzy;cztery;pięć",2,";"));
}

I czy ktoś mi wytłumaczy dlaczego ten C jest taki oporny i nie działa?
Mam pie...lony wskaźnik do stringu a, który po wyk. strstr wskazuje podobno na znaczek ';' w s, to chce w tym miejscu uciąć ten teskt, wstawiam '0' do a, a skoro a wskazuje na ';' w s, to w s powinno się te '0' znaleźć, a nie znajduje...

Czyżby w C nie działały wskaźniki na stringach???

0
char* a;
...
a="\0";

Przyjrzyj się.

0

W a to działa. Nie ważne, czy zrobię a="\0" czy a='\0' - oba zapisy mój kompilator łyka bez problemów, jeśli chodzi tobie o rodzaj apostrofów.
I jak wyświetlam zawartość a to pokazuje mi pusty string, gdy ta linijkę zakomentuję, wtedy pokazuje mi to co w s, czyli cały string.

Ale nie rozumiem tego, że skoro a to wskaźnik do s, to jakakolwiek zmiana w nim, powinna powodować zmianę w s, a nie robi tego! I to jest właśnie problem tego kodu, który próbuję zrozumieć.
W sieci znalazłem mnóstwo przykładów jak to w C fantastycznie działają wskaźniki, ale wszystkie to przykłady liczb, np. INT.

Np. taki kod:

int a = 5;
int *b;
b=a;
*b = 4;
printf("%d",a) -> wyświetli 4. Wskaźnik zmienił zawartość 5 na 4, prawidłowo!

I dokładnie to samo chciałbym uzyskać we wskaźniku, który wskazuje na znak w stringu.
Niestety jakkolwiek próbuję to zrobić, c albo pokazuje mi błąd, albo wywala się naruszeniem pamięci.

W pascalu to robi się po prostu z palca, nie ma znaczenia na co wskazuje wskaźnik, czemu w C nie da się zrobić tego tak samo prosto.
To właśnie usiłuję zrozumieć.

0
samueladama napisał(a):

W a to działa. Nie ważne, czy zrobię a="\0" czy a='\0' - oba zapisy mój kompilator łyka bez problemów, jeśli chodzi tobie o rodzaj apostrofów.
I jak wyświetlam zawartość a to pokazuje mi pusty string, gdy ta linijkę zakomentuję, wtedy pokazuje mi to co w s, czyli cały string.

Tłumacząc na Pascala, robisz coś takiego i dziwisz się że napis się nie zmienia:

var napis:array[0..255] of char = 'Ala ma kota.';

var wsk:pchar;

begin
  wsk := @napis;
  wsk := #0;
  writeln(napis);
end.

Zmieniasz wartość wskaźnika (przypisujesz doń adres innego stringa), a nie modyfikujesz wskazywany string.

0

Masz rację, niestety kodu

*a = #0;

kompilator nie akceptuje, zaś kod:
a<=#0;
jest akceptowany, ale nie daje pożądanego wyniku.

W takim razie jak zapisać w c, coś, co w pascalu wygląda następująco:

var s: string;
      p: ^char;
begin
  s:='1234556';
  p=&s[2];
  p^:='0';
  writeln(s); //=> '103456' (wynik oczekiwany)
end;
0
#include <stdio.h>

char * LineToStr(char *in_s, int in_l, char * separator){

  char *s = in_s;
  int i;
  char *a,*b;
  

  /* usuwam segmenty niepotrzebne przed */
  for (i=2;i<=in_l;i++){
    if (a=strstr(s,separator)) a++;
  }

  /* usuwam segmenty niepotrzebne po */
  if (a=strstr(s,separator)){
    a++;
    *a='\0';
    return s;
    //memcpy(s,'\0',1);

//    printf("Wskaźnik a=%s\n",a);
  }


  return in_s;
}

void main(){
  printf("tekst=%s\n",LineToStr("jeden;dwa;trzy;cztery;pięć",1,";"));
}

Kod się wywala:

[tao@earth C]$ ./compile
demo.c: In function ‘LineToStr’:
demo.c:12:11: warning: implicit declaration of function ‘strstr’ [-Wimplicit-function-declaration]
     if (a=strstr(s,separator)) a++;
           ^~~~~~
demo.c:12:11: warning: incompatible implicit declaration of built-in function ‘strstr’
demo.c:12:11: note: include ‘<string.h>’ or provide a declaration of ‘strstr’
demo.c:2:1:
+#include <string.h>
 
demo.c:12:11:
     if (a=strstr(s,separator)) a++;
           ^~~~~~
demo.c:16:9: warning: incompatible implicit declaration of built-in function ‘strstr’
   if (a=strstr(s,separator)){
         ^~~~~~
demo.c:16:9: note: include ‘<string.h>’ or provide a declaration of ‘strstr’
./compile: linia 3:  4490 Naruszenie ochrony pamięci   (zrzut pamięci) ./a.out

Dlaczego?

0

Wszystko masz napisane. Brakuje nagłówka <string.h>

Powiedz co konkretnie chcesz osiągnąć, bo *a = '0' i *a = '\0' to dwie różne rzeczy.

0
samueladama napisał(a):

Masz rację, niestety kodu

*a = #0;

kompilator nie akceptuje, zaś kod:

Bo to nie jest C.

*a = '\0';
0

Chcę zmieniać zawartość stringu za pomocą wskaźników, nie ważne czy to będzie 'A' czy '\0', bo to bez znaczenia, skoro ani jednego, ani drugiego nie udaje mi się wpisać w ten sposób.

0

Znalazłem taki kod w necie:

char *Slowa_Na_Duze( char* tekst )

        {

           char *wsk = tekst;

           if( !*wsk )        // jeżeli tekst pusty to zakończ działanie

               return(tekst);

           *wsk = toupper( *wsk );              // zamiana pierwszej litery

           while( *++wsk )

               if( *(wsk-1) == ' '  )                 // jeżeli poprzedzający znak jest spacją

                   *wsk = toupper( *wsk );       // zamiana znaku na dużą literę

           return( tekst );

        } //------------------------------------------------------------------------ Slowa_Na_Duze

Próbuję zrobić coś podobnego i u mnie to nie działa. Wytłumaczcie mi, co robię źle.
Bo jak ja u siebie próbuję podstawić jakikolwiek znak pod string podany w parametrze funkcji, to niestety zawsze kończy się to naruszeniem pamięci.

0

Dobra nie ważne, pie...przyć ten C, strasznie ograniczony ten język... Widocznie to ponad siły tego tak przez niektórych idealizowanego języka.
C dobry jest do liczb, nawet całkiem dobrze sobie z nimi radzi, niestety ze stringami nie radzi sobie wcale, nawet wy nie potraficie pomóc. Dzięki, odpuszczam sobie problem.

0

Więcej cierpliwości, bo z takim nastawieniem to za daleko nie zajdziesz.

Chcę zmieniać zawartość stringu za pomocą wskaźników, nie ważne czy to będzie 'A' czy '\0', bo to bez znaczenia, skoro ani jednego, ani drugiego nie udaje mi się wpisać w ten sposób.

   char *tab = "napis";
   printf("%s\n", tab);
   tab[0] = 'd';
   printf("%s\n", tab);

Dobrze rozumiem? Chcesz zrobić coś takiego jak w powyższym kodzie? To się nie uda, bo nie możesz modyfikować takiego ciągu znaków, to jest stały literał.
Ale możesz tak jak poniżej:

   char tab[] = "napis";
   printf("%s\n", tab);
   tab[0] = 'd';
   printf("%s\n", tab);

Tutaj już masz tablicę znaków i możesz ją bez problemu modyfikować.

Przykład z użyciem funkcji:

void change_letter(char *tab)
{
    tab[0] = 'd';
}

int main()
{
   char tab[] = "napis";
   printf("%s\n", tab);
   change_letter(tab);
   printf("%s\n", tab);

    return 0;
}

Chyba, że nie rozumiem co próbujesz zrobić. Jeśli coś powiedziałem źle to mnie poprawcie.

0

A w tym warunku drugiego if'a nie powinienes porownywac zamiast przypisywac?

2
samueladama napisał(a):

Dobra nie ważne, pie...przyć ten C, strasznie ograniczony ten język... Widocznie to ponad siły tego tak przez niektórych idealizowanego języka.
C dobry jest do liczb, nawet całkiem dobrze sobie z nimi radzi, niestety ze stringami nie radzi sobie wcale, nawet wy nie potraficie pomóc. Dzięki, odpuszczam sobie problem.

To, że nie rozumiesz komunikatów kompilatora i nie odróżniasz char od char*, to bynajmniej nie znaczy, że język jest ograniczony.

0
zdz napisał(a):

Więcej cierpliwości, bo z takim nastawieniem to za daleko nie zajdziesz.

kol. Pierwotny Pytający ma to gdzieś.
A sposób mówienia o kodzie (zarypanym / skopiowanym skądkolwiek) jest typowy dla arduinowców

samueladama napisał(a):

Jest sobie pewien kod w C:

Lub jeszcze w liczbie mnogiej "są takie kody" (w domniemaniu C++ jest kiepskie, bo owe kody są złośliwe i nie chcą razem działać)

0

Pytający nie ma niczego gdzieś, kiedyś pisał w C, ale to było dawno, stąd doskonale wiedział, że to powinno działać, ale zapomniał... Wiem co robiłem źle!
Mój błąd polegał na tym, że próbowałem zmienić coś, czego zmieniać nie powinienem. A rozwiązanie okazało się bardzo proste. Memcpy też nie działało, bo próbowałem przypisać wartość w tej funkcji, kiedy tak naprawdę powinienem podać wskaźnik do już istniejącej funkcji. Więc zrobiłem to następująco:

char n = '\0';
memcpy(&a[b-a],&n,1);

Całość działa, a kod wygląda następująco:

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

char *s;
int s_count;

char* LineToStrTest(char *in_s, int in_l, char *separator){
  return "test";
}


char* LineToStr(char *in_s, int in_l, char *separator){

  int i = strlen(in_s)+1;
  
  if (s_count==0){
    s_count = i;
    s = malloc(s_count);
  } else {
    if (s_count<i){
      free(s);
      s_count = i;
      s = malloc(s_count);
    }
  }
  
  strcpy(s,in_s);
  char *a = s;
  char *b = s;
  char n = '\0';

  /* usuwam segmenty niepotrzebne przed */
  for (i=2;i<=in_l;i++){
    if (a){
      a=strstr(a,separator);
      if (a) a++;
    } else break;
  }

  /* usuwam segmenty niepotrzebne po */
  if (a) {
    if (b=strstr(a,separator)){
      memcpy(&a[b-a],&n,1);
    }
  } else return "";
  printf("a=%s\n",a);
  return a;
}

void __attribute__ ((constructor)) my_init(void) {
  s_count = 0;
}

void __attribute__ ((destructor)) my_fini(void) {
  if (s_count>0)
  {
    free(s);
    s_count = 0;
  }
}

/*
void main()
{
  printf("Wynik=%s\n",LineToStr("1;2;3;4;5",3,";"));
}
*/

A teraz co chciałem osiągnąć? Chciałem napisać kawałek biblioteki, w której po podaniu ciągu ograniczonego stałym separatorem, kod wyciągnie mi z niego żądany n-ty element, biorąc pod uwagę warunek, by elementy ujęte w apostrofach były brane całkowicie niezależnie od tego, czy wewnątrz nich były by użyte znaki separatora. Kod nie został skończony, bo próbowałem rozwiązać problem, który mi wskoczył... poza tym okazało się, że ten kod wykonuje się o wiele dłużej, niż ten sam kod napisany pod Lazarusem, myślałem, że odpowiednia funkcja w C przyśpieszy mi działanie tego kodu w pewnym programie, gdzie używam tego dosyć sporo... Jednak kod w Pascalu działa mi o wiele szybciej. Wywołanie takiej pustej funkcji to powoła czasu działaniu mojej w pascalu... Gdyby udało mi się to napisać tak by wykonywało się choć 2 razy szybciej, to byłby sens to dokończyć. Ale takie właśnie były założenia. Pewnie można było by ten kod jeszcze zoptymalizować i pozbyć się niepotrzebnych if-ów, pewnie się tym jeszcze pobawię, bo mnie ciekawość zżera. Dzięki za pomoc, dalej poradzę sobie już sam. Pozdro!

0

Poprawka! Zapomniałem usunąć printf-a z kodu funkcji, to stąd to wykonywało się tak długo! Funkcja wykonuje się przynajmniej ze 3 razy szybciej niż to samo co mam w Pascalu! To ma jednak sens! Wiedziałem, że w C powinno być szybciej! Jeszcze raz dzięki chłopaki! Dodam obsługę ciapek, zoptymalizuję kod i będę miał to o co mi właśnie chodziło! Pozdrowienia!

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