Gå til innhold

Char og memory address


Anbefalte innlegg

Har nå bestemt meg for å lære C++ skikkelig godt, og har drevet med C++ hver dag siden jeg startet.

 

Men idag kom jeg over noe jeg ikke helt skjønner.

Jeg mener selv at jeg forstår Pointers forholdsvis godt, og har ikke hatt noe problem med å bruke pointers tidligere.

 

Men idag ville jeg sjekke minneadressen til en char, og det var da jeg ble sittende som et lite spørsmålstegn.

 

 

Bilde:

http://bildr.no/view/356466

 

Hva er det som skjer her? Hvorfor er minneadressen så "rar"?

 

Kode:

#include <iostream>
#include <windows.h>
#include <string>

using namespace std;

void mani(char *);

int main()
{
char x = 'T';

char * ptr = &x;

cout << "X is: " << *ptr << endl;
cout << "Mem. address of X: " << & << endl;

cout << endl;

mani(ptr);

cout << "X is: " << *ptr << endl;
cout << "Mem. address of X: " << ptr << endl;



char f;
cin >> f;
return 0;
}

void mani(char * ptr1)
{
(*ptr1) = 'A';
}

 

 

Håper noen kan fortelle meg hva som skjer med minneadressen! :-)

 

 

//s1gh

Endret av Sigh
Lenke til kommentar
Videoannonse
Annonse

Grunnen til dette er at noen funksjoner oppfatter peker-til-char som C-strings.

 

Strings i C er en array med char-s som slutter på 0 (nullbyten). Når man skal sende en C-string til funksjoner sender man en peker til første char i arrayet. Det er slik at noen funksjoner regner med at hvis du sender den en peker-til-char, så er det en C-string. Altså, siden du kaller << med en peker-til-char, regner << med at du vil skrive ut en C-string, og ikke minneadressen til char-en du peker til.

 

#include <cstdio> /* For printf. */
#include <iostream>
using std::cout;
using std::endl;

void print_string(char *str);

int main()
{
char cstring[] = {'H', 'e', 'i', 's', 'a', 'n', 'n', '!', 0};
char another[] = "Heisann!"; /* Automatisk nullbyte på slutten. */
char *ptr;
char ch = 'A';

cout
	<< "A C-string: " << cstring << endl
	<< "Another: " << another << endl;

/* printf gir mer kontroll over hvordan
 * argumenten skal oppfattes.
 */
printf("My char is %c and its address is %x\n", ch, &ch);

print_string(cstring);
cout << endl;

return 0;
}

/* Dette er hvordan << oppfatter en
* peker-til-char og hva den gjør.
*/
void print_string(char *ptr)
{
while (*ptr)
	cout << *ptr++;
}

 

Så det er ikke noe galt med oppfattelsen din, det er bare hvordan cout sin << oppfatter det du gir den.

 

Så hvorfor du ser garble når du prøver å printe ut minneadressen er fordi << regner med at det er C-string du vil printe ut. Den printer så ut hver char i minnet fra og med der hvor tegnet ligger helt til den når en nullbyte.

 

Hvis du vil bruke cout til å vise minneadressen til en char kan du caste peker-til-char-en til en peker-til-int f eks:

 

char ch = 'A';

cout << "My char is " << ch << " and its address is " << (int *)&ch << endl;

Endret av LostOblivion
Lenke til kommentar

Ahh, tusen takk for en fantastisk forklaring! :-)

 

Men jeg har ett spørsmål til. Det dreier seg ikke om pointers eller noe i den kategorien, men om printf.

 

F.eks: printf("My char is %c and its address is %x\n", ch, &ch);

 

Har sett flere som bruker %<bokstav>, men hva er egentlig disse "tegnene"?

 

Svaret er sikkert veldig logisk og simpelt, men jeg spør likevel! :-)

Endret av Sigh
Lenke til kommentar
Men jeg har ett spørsmål til. Det dreier seg ikke om pointers eller noe i den kategorien, men om printf.

F.eks: printf("My char is %c and its address is %x\n", ch, &ch);

Har sett flere som bruker %<bokstav>, men hva er egentlig disse "tegnene"?

Svaret er sikkert veldig logisk og simpelt, men jeg spør likevel! :-)

Det aller beste svaret jeg kan gi deg er å droppe alt som har med printf() og lignende funksjoner å gjøre, og heller bruke andre output-mekanismer som for eksempel cout.

 

Men hvis du nå likevel av ren nysgjerrighet vil vite hva som foregår i printf(), så kan jeg forklare.

printf() er en funksjon med variabelt antall parametere. Det betyr at du kan angi så mange parametere du vil. Den første parameteren er en kontrollstreng. Den ser ut som en hvilken som helst annen tekststreng, bare at den kan inneholde kontrolltegn, som du lett gjenkjenner ved at de begynner med %.

Hvis du teller antall slike kontrolltegn, skal det være samme antall av disse som av parametere etter kontrollstrengen. I eksemplet ditt er det to kontrolltegn (%c og %x), og to parametere etter kontrollstrengen (ch og &ch).

Det printf gjør, er å dytte inn verdiene av de resterende parametrene der hvor kontrolltegnene står, i samme rekkefølge. Bokstaven(e) etter prosenttegnet forteller hvilken datatype printf() skal tolke parametrene som.

 

Her er en oversikt over verdiene:

http://msdn.microsoft.com/en-us/library/hf4y5e3w(VS.71).aspx

I tillegg til typebetegnelser kan kontrolltegnene inneholde informasjon om lengde/presisjon på feltet:

http://msdn.microsoft.com/en-us/library/56e442dc(VS.71).aspx

 

Men som sagt, styr unna printf() og lignende, og skriv til skjerm med cout heller. :)

Endret av alfred97
Lenke til kommentar

Tusen takk for forklaringen! :-)

 

Hehe, jeg spurte egentlig bare av ren nysgjerrighet.

 

Ettersom jeg nå lærer meg C++, vil jeg helst vite hvordan alt fungerer, og hvordan ting henger sammen, uansett om jeg ikke kommer til å bruke det senere.

 

Så uansett om printf ikke er å anbefale, ville jeg bare vite hvordan det fungerte. :-)

Lenke til kommentar
Hvorfor? printf fungerer utmerket.

Har aldri påstått at det ikke funker. Hvis man absolutt vil holde seg til C-syntaks, så er det ikke noe i veien for å bruke printf.

Jeg sier bare at man får renere kode med cout når man koder i C++. Stream-operatorene gir ordentlig typesjekking, passer på at antallet parametere er rett (prøv printf med en kontrollkode for mye), og etter min mening gjør det koden lettere å lese. Sistnevnte er det selvfølgelig opp til hver enkelt å ha sine egne meninger om.

 

 

Hvordan formaterer en output med cout da? Hvis du bare vil se PI med 4 desimaler for eksempel.

Tja, du kan jo prøve noe sånt som dette, for eksempel:

#include <iostream>
#include <iomanip>

int main (int argc, char **argv)
{
  const double PI = 3.14159265358979;

  std::cout << std::fixed << std::setprecision(4) << PI << std::endl;
  std::cin.get();
} // main

Lenke til kommentar

Off Topic:

Jeg foretrekker egentlig C framfor C++ når jeg kan, så det ville vært en overraskelse om jeg sa noe annet. En mening jeg nok deler med en del andre er at C++ er et svært klønete forsøk på objektorientering. På tiden C++ ble født var det nok ansett som fremragende, men i dag sammenlignet med godt implementerte objektorienterte språk som C#, virker det svært klønete. C++0x virker også desto mer klønete jo mer jeg leser om det.

 

Det sier deg selv når en blanding av et rent funksjonelt språk som C og objektorientering prøver å blandes sammen, så blir ikke resultatet mindre rotete.

 

Svært funksjonelt og nyttig, men utrolig rotete. Det er som en dårlig versjon av Win32 biblioteket...

 

Lenke til kommentar
cout er da uten tvil å foretrekke over printf. Ikke bare er det normen i C++ å bruke cout fremfor printf, men det er også mer fleksibelt og jeg synes at det ser bedre ut også. Prøv f.eks. å "operator-overlaste printf" for å skrive ut en egendefinert type. Det blir jo klønete. :p

Skriv deg to små programmer som skriver ut en tekststreng 1000000 ganger med printf og cout. Ta tiden på hver av dem via "time" et par ganger.

 

Off Topic:

Jeg foretrekker egentlig C framfor C++ når jeg kan, så det ville vært en overraskelse om jeg sa noe annet. En mening jeg nok deler med en del andre er at C++ er et svært klønete forsøk på objektorientering. På tiden C++ ble født var det nok ansett som fremragende, men i dag sammenlignet med godt implementerte objektorienterte språk som C#, virker det svært klønete. C++0x virker også desto mer klønete jo mer jeg leser om det.

 

Det sier deg selv når en blanding av et rent funksjonelt språk som C og objektorientering prøver å blandes sammen, så blir ikke resultatet mindre rotete.

 

Svært funksjonelt og nyttig, men utrolig rotete. Det er som en dårlig versjon av Win32 biblioteket...

C er ikke et funksjonelt språk. Det er et imperativt språk.

Lenke til kommentar
Forsåvidt hva denne samtalen er verdt, er forskjellen på et funksjonelt språk og et imperativt språk pirk, er du ikke enig?

 

Hele posten din var offtopic. Harkonnen kommenterte på topic-relatert post, og i TILLEGG på din.

Edit: I tillegg er det en enorm forskjell på imperative og funksjonelle språk.

Endret av jurg
Lenke til kommentar
Det sier deg selv når en blanding av et rent funksjonelt språk som C og objektorientering prøver å blandes sammen, så blir ikke resultatet mindre rotete.

 

C er ikke funksjonelt, det er prosedyrebasert, men ikke funksjonelt...med mindre du mener et språk som fungerer. :)

 

edit: D'oh! burde lese gjennom alle poster først :p

Endret av GeirGrusom
Lenke til kommentar

Trådstarter har fått svar på sine spørsmål, så med mindre noen har noe å tilføye på akkurat det punktet, så er egentlig alle innlegg off-topic.

 

Når det gjelder dette med ytelse på cout vs. printf, så må det selvsagt innrømmes at printf er en del raskere. Jeg kjørte nettopp en kjapp test som viste at 100 000 kall til printf tok ca. 30-35% av den tida som gikk med til tilsvarende sekvens av cout, med samme output.

Dette er åpenbart en avveining som må gjøres. Slik jeg oppfatter det, er ytelsen på tekstutskrift sjelden noe tema, og dermed er det en overkommelig pris å betale for de fordelene jeg nevnte ovenfor. Med cout greier du uansett å skrive ut tekst ganske mye fortere enn brukeren greier å lese den.

Men hvis ytelsen av en eller annen grunn skulle være så kritisk at forskjellen mellom cout og printf blir avgjørende, så må man selvfølgelig bruke den fremgangsmåten som best løser problemet. Sånn er verden - for å oppnå en ting, gir man avkall på noe annet.

 

Beklager at jeg sier det, men denne begrepsonanien deres bidrar i grunnen ikke til annet enn å forvirre, og til å fremstille dere selv som kranglevorne nerder. Jeg jobber som utvikler, og har hittil ikke vært borti en problemstilling som jeg ikke kunne løse fordi jeg ikke kjenner til forskjellen mellom "imperative" og "funksjonelle" språk.

Lenke til kommentar
Beklager at jeg sier det, men denne begrepsonanien deres bidrar i grunnen ikke til annet enn å forvirre, og til å fremstille dere selv som kranglevorne nerder. Jeg jobber som utvikler, og har hittil ikke vært borti en problemstilling som jeg ikke kunne løse fordi jeg ikke kjenner til forskjellen mellom "imperative" og "funksjonelle" språk.
Takk! Akkurat det jeg mener med pirking...
Lenke til kommentar
Beklager at jeg sier det, men denne begrepsonanien deres bidrar i grunnen ikke til annet enn å forvirre, og til å fremstille dere selv som kranglevorne nerder. Jeg jobber som utvikler, og har hittil ikke vært borti en problemstilling som jeg ikke kunne løse fordi jeg ikke kjenner til forskjellen mellom "imperative" og "funksjonelle" språk.
Takk! Akkurat det jeg mener med pirking...

 

Begrepsonani? Hvordan forvirrer det at noen påpeker at C ikke er et funksjonelt språk? Det er jo bare sannheten. Det er stor forskjell på funksjonelle og imperative språk, så la oss kalle en spade for en spade.

 

Gratulerer, at du ikke har hatt noe problem med å løse en problemstilling betyr ikke at det er en uviktig forskjell. Jeg kan forstå at folk reagerer slik når man får kommentarer som "Det heter ikke linux men GNU/Linux!!!1", men akkurat her var det en kurant korreksjon.

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...