• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

tablice znaków w strukturze

Object Storage Arubacloud
0 głosów
356 wizyt
pytanie zadane 15 kwietnia 2019 w C i C++ przez SeekingAnswers Nowicjusz (140 p.)
#include <iostream>
#include <fstream>
#include <cstring>
#include <string>

using namespace std;

struct Struktura{

char Imie[20];
char Nazwisko[20];
int IQ;

};

int main()
{
    Struktura s1;

    string imie="Jas";
    string nazwisko="Fasola";
    strncpy(s1.Imie,imie.c_str(),20);
    s1.Imie[imie.length()+1]='\0';
    strncpy(s1.Nazwisko,nazwisko.c_str(),20);
    s1.Nazwisko[nazwisko.length()+1]='\0';
    s1.IQ=200;
    

Witam, chciałbym zapytać Was o inne prostsze sposoby na uzupełnienie tablic znaków po utworzeniu instancji struktury analogicznie do przykładu powyżej. Powyższy kod spełnia swoją rolę, jednakże wydaje mi się dość skomplikowany, stąd moje pytanie. Serdecznie dziękuję za wszystkie wskazówki i próby pomocy :)

 

1 odpowiedź

0 głosów
odpowiedź 15 kwietnia 2019 przez criss Mędrzec (172,590 p.)

Przede wszystkim, bez powodu używasz std::string w tym kodzie. Po drugie: kod kopioania stringa do tablic charów jest lekko niepoprawny, bo np. w przypadku imienia kopiujesz 20 bajtów podczas gdy wystarczyłoby skopiować 4 (3 składający się na słowo "Jas" i kończące 0). Nie jest to problemem gdy tylko czytasz z adresu zwróconego przez c_str(), ale jednak wychodzisz poza pamięć stringa i w efekcie niepotrzebnie kopiujesz jakieś śmieci, które i tak nie mają żadnego znaczenia. Mógłbyś po prostu użyć strcpy zamiast strncpy, ponieważ strcpy sam sobie ustala gdzie string się kończy kopiując do momentu aż natrafi na 0 (razem z zerem). Także również niepotrzebnie "manualnie" ustawiasz kończące 0, bo zostało już przekopiowane podczas strncpy (i tak samo stanie się przy strcpy). Także mogłoby to wyglądać tak:


#include <iostream>
#include <fstream>
#include <cstring>
#include <string>
 
using namespace std;
 
struct Struktura{
 
char Imie[20];
char Nazwisko[20];
int IQ;
 
};
 
int main()
{
    Struktura s1;
 
    strcpy(s1.Imie, "Jas");
    strcpy(s1.Nazwisko, "Fasola");
    s1.IQ=200;
}
komentarz 15 kwietnia 2019 przez SeekingAnswers Nowicjusz (140 p.)

Bardzo dziękuję za odpowiedź. Rozumiem, że przy podaniu do funkcji strcpy napisu dłuższego niż tablica do której go kopiujemy, napis zostanie ucięty oraz zabraknie w tablicy miejsca na znak '/0' kończący napis. Stąd przy próbie wypisania takiej tablicy znaków na ekran, wypisanie zakończy się dopiero przy napotkaniu '/0' gdzieś w kolejnych bajtach pamięci występujących po tablicy (o ile gdzieś tam jest). Istnieje jakiś mechnizm ucinający odpowiednio kopiowany napis, aby ostatnią pozycję zajmował znak '/0/?

komentarz 15 kwietnia 2019 przez criss Mędrzec (172,590 p.)

Rozumiem, że przy podaniu do funkcji strcpy napisu dłuższego niż tablica do której go kopiujemy, napis zostanie ucięty 

Nie, strcpy nie ma skąd wiedzieć jak długa jest tablica docelowa. Więc kopiowanie będzie trwało nadal, ale do pamięci za tablicą. 

Oh, źle ci powiedziałem odnośnie strncpy. ta funkcja też kończy jeśli natrafi na 0 w kopiowanym stringu. Także jak najbardziej sensownie jest z niej korzystać. Także wybacz za wprowadzanie w błąd :)

Cytat dokumentacji:

Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of numcharacters have been written to it.

 

komentarz 16 kwietnia 2019 przez SeekingAnswers Nowicjusz (140 p.)
#include <iostream>
#include <fstream>
#include <cstring>
#include <string>

using namespace std;

struct Struktura{

char Imie[20];
char Nazwisko[20];
int IQ;

};

int main()
{
    Struktura s1;

    strcpy(s1.Imie, "Jaaaaaaaaaaaaaaaaaaaaaaas");
    strcpy(s1.Nazwisko, "Fasola");
    s1.IQ=200;
 cout<<"Imie: "<<s1.Imie<<" Nazwisko: "<<s1.Nazwisko<<" IQ: "<<s1.IQ<<endl;

Powyższy kod wypisuje na ekranie:

Przy wypisaniu tablicy s1.Imie wypisuje razem z nią tablice s1.Nazwisko. Dlaczego otrzymuję taki rezultat? Wiem że napis, który próbuje umieścić w tablicy s1.Imie jest za długi, lecz jak Pan wyżej napisał pozostałe (nadmiarowe) znaki tego napisu umieszczone są dalej poza tablicą, a wśród nich takżę znak "null-character", który powinien zakończyć wypisywanie napisu na ekran, natomiast wypisywanie kończy się dopiero na znaku '/0' w tablicy s1.Nazwisko. W którym miejscu moje myślenie jest niepoprawne?

komentarz 16 kwietnia 2019 przez SeekingAnswers Nowicjusz (140 p.)
edycja 16 kwietnia 2019 przez SeekingAnswers
for(int i=0;i<26;i++){
        cout<<*(s1.Imie+i);
    }

Użyłem powyższego kodu do wyświetlenia kolejnych komórek tablicy i komórek bezpośrednio za nią. Otrzymałem:

Rozumiem, że ostatnie znaki napisu "Jaaaaaaaaaaaaaaaaaas" niemieszczące się w tablicy s1.Imie, zostały skopiowane przez funkcję strcpy do pamięci za tablicą, ale następne wywołanie tej funkcji dla s1.Nazwisko nadpisało te komórki pamięci.

Przepraszam za chaotyczność postów, ale bardzo mi zależy na zrozumieniu tego zjawiska :)

komentarz 16 kwietnia 2019 przez criss Mędrzec (172,590 p.)

Rozumiem, że ostatnie znaki napisu "Jaaaaaaaaaaaaaaaaaas" niemieszczące się w tablicy s1.Imie, zostały skopiowane przez funkcję strcpy do pamięci za tablicą, ale następne wywołanie tej funkcji dla s1.Nazwisko nadpisało te komórki pamięci.

Tak, myślę, że dobrze tutaj rozumiesz.

Dla jasności jeszcze wytłumacze:

 Musisz pomyśleć o pamięci struktury całościowo. Teraz wygląda to tak:

<Imie 20 bajtów>|<Nazwisko 20 bajtów>|<IQ 4 bajty>

Po przekopiowaniu do Imie ciągu o długości np. 25 (nie wliczając 0, tak jak to robisz teraz) "Jaaaaaaaaaaaaaaaaaaaaaaas", pamięć wygląda tak (kropkami oznaczam bajty o niewiadomej wartości):

Jaaaaaaaaaaaaaaaaaaa | aaaas0.............. | ....

Następnie do Nazwisko wkopiowujesz "Fasola":

Jaaaaaaaaaaaaaaaaaaa | Fasola0............. | ....

Zauważ, że najbliższy bajt o wartości 0 od początku struktury znajduje się dopiero za napisaem "Fasola". Dlatego wypisując Imie, wypisywanie kończy się dopiero za "Fasola" - na najbliższym zerze.

komentarz 17 kwietnia 2019 przez SeekingAnswers Nowicjusz (140 p.)
Dziękuję bardzo :)

Podobne pytania

0 głosów
4 odpowiedzi 152 wizyt
pytanie zadane 7 czerwca 2018 w C i C++ przez Sansi Użytkownik (720 p.)
0 głosów
1 odpowiedź 2,015 wizyt
pytanie zadane 8 listopada 2015 w C i C++ przez Cinas Nowicjusz (160 p.)

92,555 zapytań

141,403 odpowiedzi

319,557 komentarzy

61,940 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...