Odpowiednik string w C (istnieje)? Problem przypisywania dużej ilości tekstów do tablicy.

Odpowiednik string w C (istnieje)? Problem przypisywania dużej ilości tekstów do tablicy.
DA
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 98
0

Muszę chwilowo korzystać z C (środowisko gcc) i mam dużą tablicę tekstów :

Kopiuj
char text[10000][512];

Owa tablica szczytuje sobie dane z tekstu ułożonego w rzędach metodą z użyciem funkcji strcpy()

Kopiuj
strcpy(text[licznik],"kolejny rząd tekstu");


Mam pytanko a w zasadzie dwa, czy można użyć jakiejś alternatywnej metody podobnej do przypisania stringów w C++, pozbywając się jednocześnie konieczności użycia strcpy()?
Cos jak:

Kopiuj
string text[10000];
text[licznik]="kolejny rzad tekstu";

Wiem, że można bawić się przypisywaniem z użyciem nawiasów klamrowych, ale w przyadku dużych ilości danych traci to sens,
I drugie pytanko. Co się stanie jeżeli do przypisania funkcji strcpy() wystąpi pusta linia tekstu?

Kopiuj
strcpy(text[licznik],pusta_linia);


i wtedy z automatu będzie się to równać?

Kopiuj
text[licznik]='\0';

A w momencie gdyby zmienna text nie była by jednak statyczną tablicą a dynamiczną char** text budowaną i zwalniana poprzez malloc/free to takie przypisywane - puste linie w tekscie nie spowodowały by segmentation faul czy czegos podobnego z pamięcią?

Miang
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1868
0
davout napisał(a):

Owa tablica szczytuje

co robi??????????? 😺

i wtedy z automatu będzie się to równać?

Kopiuj
text[licznik]='\0';

poczytaj troch e o stringach w c i co to jest "\r\n"

MarekR22
  • Rejestracja: dni
  • Ostatnio: dni
2

Strasznie brakuje kontekstu, co twój kod właściwie robi.
Jeśli te dane są statyczne (twardo wpisane w program), to można zrobić tak:

Kopiuj
const char text[][512] = {
   "Tekst pierwszy",
   "Tekst drugi",
   "Tekst trzeci",
   ....
   "Tekst ostatni"
};

Jeśli stały limit na długość tekstu nie przeszkadza, to można też to obejść za pomocą struktury:

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

typedef struct Text {
    char s[512];
} Text;

int main(void)
{
    Text a = { "ala ma kota" };
    Text b = { "tomek ma psa" };

    printf("Text a: %s\n", a.s);
    printf("Text b: %s\n", b.s);

    b = a;
    a = (Text){ "karolina ma konia" };
    
    printf("Text a: %s\n", a.s);
    printf("Text b: %s\n", b.s);
}

https://godbolt.org/z/s8fzzKvh7

DA
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 98
0
MarekR22 napisał(a):

Strasznie brakuje kontekstu, co twój kod właściwie robi.
Jeśli te dane są statyczne (twardo wpisane w program), to można zrobić tak:

Kopiuj
const char text[][512] = {
   "Tekst pierwszy",
   "Tekst drugi",
   "Tekst trzeci",
   ....
   "Tekst ostatni"
};

Jeśli stały limit na długość tekstu nie przeszkadza, to można też to obejść za pomocą struktury:

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

typedef struct Text {
    char s[512];
} Text;

int main(void)
{
    Text a = { "ala ma kota" };
    Text b = { "tomek ma psa" };

    printf("Text a: %s\n", a.s);
    printf("Text b: %s\n", b.s);

    b = a;
    a = (Text){ "karolina ma konia" };
    
    printf("Text a: %s\n", a.s);
    printf("Text b: %s\n", b.s);
}

https://godbolt.org/z/s8fzzKvh7

Dziękuję i oto mi chodziło. Dla mnie już wszystko jasne. A te "szczytuje" to wypadek przy pracy, choć bardziej podejrzewam dywersje chińskiego smartphona. Jeszcze raz dzięki. Te C coraz bardziej mi się podoba.

KS
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 748
0
Kopiuj
strcpy(text[licznik],"kolejny rząd tekstu");

chyba miało być
strcpy( &text[licznik],"kolejny rząd tekstu");
DA
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 98
0
ksh napisał(a):
Kopiuj
strcpy(text[licznik],"kolejny rząd tekstu");

chyba miało być
strcpy( &text[licznik],"kolejny rząd tekstu");

Pewnie jest tak jak piszesz, nie jestem mocny w te klocki. Przy czym mój sposób gdzie jest zmienna tablicowa, a nie adres zmiennej kompilował się poprawnie, program działał, nawet nie było "warningów".

lion137
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 5068
1

Kiedyś się bawiłem w takie coś, możesz rzucić okiem.
https://github.com/lion137/C_datastructures/blob/master/strings/cstring.c

CA
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 5
0

takie duże tablice to lepiej alokować na stercie

elwis
  • Rejestracja: dni
  • Ostatnio: dni
1

Skąd te teksty są wczytywane? Jeśli z pliku to możesz sobie zmapować do pamięci (mmap na Linuksie, CreateFileMapping na Windowsie). Wtedy wystarczy przepisać wskaźniki do kolejnych linijek. Przed każdą linijką pliku możesz sobie dopisać jej długość i wtedy nawet nie będziesz musiał na piechotę liczyć ich długości.

Jeśli wczytujesz ze strumienia to chyba jest to tylko o tyle trudniejsze, że nie znasz z góry docelowej długości wszystkich tekstów, chyba, że zostaną podane w nagłówku. Dalej już analogicznie. W każdym razie nie ma potrzeby nic przepisywać.

Program wczytujący ze standardowego wejścia z nagłówkiem zawierającym ilość linii i całkowity rozmiar danych mógłby wyglądać tak:

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

int main(int argc, char** argv) {
    size_t amount,total;

    fread(&amount, sizeof(size_t), 1, stdin);
    fread(&total, sizeof(size_t), 1, stdin);

    char* string_buff = malloc(total);
    fread(string_buff, 1, total, stdin);

    char **strings = malloc(amount * sizeof(char*));

    char *cur = string_buff;
    for(size_t i = 0; i < amount; i++) {
        strings[i] = cur + sizeof(size_t);
        size_t len = *((size_t*)cur);
        cur += len + sizeof(size_t);
    }

    printf("amount: %lu\ntotal: %lu\n", amount, total);
    for(size_t i = 0; i < amount; i++) {
        printf("%s\n", strings[i]);
    }

    free(strings);
    free(string_buff);
}

Natomiast program generujący dane testowe tak:

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

int main(int argc, char** argv) {
    FILE* output = fopen("out.dat", "w");
    size_t amount = 0;
    size_t total = 0;

    fwrite(&amount, sizeof(size_t), 1, output);
    fwrite(&total, sizeof(size_t), 1, output);

    char buff[2048];
    while(fgets(buff, 2048, stdin)) { 
        size_t len = strlen(buff);
        buff[len-1] = 0;

        fwrite(&len, sizeof(size_t), 1, output);
        fwrite(buff, 1, len, output);
        total += len + sizeof(size_t);
        amount++;
    }

    fseek(output, 0, SEEK_SET);
    fwrite(&amount, sizeof(size_t), 1, output);
    fwrite(&total, sizeof(size_t), 1, output);

    fclose(output);
}

Dla łatwości pisania i czytania, pominąłem obsługę błędów. Tak samo pominąłem przypadek w którym mamy linię dłuższą niż 2048. Poza tym, program nie zakłada (a jeśli dane miałyby chodzić po sieci, należałoby), że nadawca ma inną architekturę niż odbiorca (inne długości typów, inną kolejność bajtów).

W przypadku braku nagłówka z długością danych, należałoby by używać realloc, żeby progresywnie powiększać bufor.

Jako ciekawostkę dodam, że w standardzie C99 można deklarować tablice o zmiennym rozmiarze, więc deklaracja strings w pierwszym kodzie mogłaby wyglądać tak:

Kopiuj
char *strings[amount];

Wówczas należy pominąć free(strings). Na gcc działa.

M9
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 54
0

Wczytujesz tablice char dwuwymiarowa.
Można to zrobić na dwa sposoby:
(1) Wczytanie po literach
(2) Wczytanie stringow czyli słów.
I później przechodzisz po tablicy dwuwymiarowej by uzyskać rezultat. Pytanie co chciałbyś uzyskać? (Może pomogę)

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.