webForumDet fria alternativet

Pragmatik / const

10 svar · 450 visningar · startad av Tobias

TobiasMedlem sedan jan. 200133 inlägg
#1

Hej!

Ira Pohl anser i sin bok Object - oriented programming using C++ att när man skickar strängar (char* s) till en funktion ska man ge dem const (const char* s) om de ej ska modifieras i funktionen. När jag initierar variabeln namn (char* ) så här får jag "assignment to 'char *' from 'const char *' discards qualifiers. Lustigt för jag ändrar ej _name i funktionen:

I klass Person:

void assign_name (const char* _name) {
name = _name;
}
...
private :
char* name;
...

i main:

Person p1;
p1.assign_name("Kalle Kula");

---
Jag testade att göra en funktion som motsvarar strlen i <cstring>, den kunde jag ropa på med const char*.

------------------
Med vänliga hälsningar

Tobias Bohlin

[Redigerat av Tobias den 30 jul 2001]

ChainsawMedlem sedan sep. 20001 124 inlägg
#2

Du gör ju char-pekaren modifierbar, det är det som kompilatorn klagar på. Titta lite på dessa rader:

const char *p1 = "Hoho!";
char *p2 = p1;
p2[2] = 'p';
Titta på tredje raden. Det här är helt lagligt. Däremot så är inte den andra raden det, där omvandlar du pekaren från const till modifierbar.

------------------
Även seriemördare är människor. http://www.choppingblock.org/
Absolut bästa episoden: http://www.choppingblock.org/d/20000925.html

TobiasMedlem sedan jan. 200133 inlägg
#3

Det som står till höger om tilldelningsoperatorn förändras inte, om vi för ett ögonblick bortser från ev. pekar-problematik. i cstring library ser strcpy ut så här:

char* strcpy (char* s1, const char* s2) {
int i;
for (i = 0; s1 = s2; ++i) {
;
}
return s1;
}

Vad är skillnaden mot min assign? Funktionen strcpy är ur boken. Jag får samma kompileringsfel när jag i main ropar på den med char* test = strcpy("hej", "svejs");
Aliasing mha & funkar inte:
void assign_name (const char& _name) {
name = _name;
}

------------------
Med vänliga hälsningar

Tobias Bohlin

UlfTMedlem sedan maj 20018 027 inlägg
#4

Felet i ditt exempel är den typkontroll som C/C++ har. Du har datatypen "const char *" på en variabel och försöker tilldela variabelvärdet till en variabel av en helt annan datatyp, nämligen "char *". Du kan få igenom ditt exempel genom kompileringen med hjälp av en typecast till "char *".

strcpy-funktionen som du jämför med, skiljer sig på en väsentlig punkt från ditt exempel. Där är det "char" på båda sidor om "=", alltså samma datatyp rakt igenom.

TobiasMedlem sedan jan. 200133 inlägg
#5

"strcpy-funktionen som du jämför med, skiljer sig på en väsentlig punkt från ditt exempel. Där är det "char" på båda sidor om "=", alltså samma datatyp rakt igenom."

Hej igen. Jag har svårt att se det så. När jag ändrar i assign till:
void assign_name (const char* _name) {
name = _name[2];
}

får jag samma kompileringsfel. Tänkte att det kanske går om man har array på högersidan om =. Så vitt jag fattar är det så det görs i strcpy. Testade den och den funkade.

------------------
Med vänliga hälsningar

Tobias Bohlin

UlfTMedlem sedan maj 20018 027 inlägg
#6

Hej,

I ditt nya exempel är du ännu mer fel ute. Här försöker du nämligen tilldela en "char" till en "char *". De variabeltyperna inte bara betraktas olika, de är verkligen olika. "char" är ett tecken, "char *" är en minnesaddress. Skulle du göra en typecast till "char *" här skulle koden kanske gå igenom kompileringen, men du skulle få stora problem när du kör programmet och "name" plötsligt pekar mot någon nonsensaddress.

Array på högersidan skulle funka för då skulle du verkligen ha "char" på båda sidor. Kom bara ihåg att gå igenom strängen tecken för tecken precis som det görs i strcpy.

Lycka till!

ChainsawMedlem sedan sep. 20001 124 inlägg
#7

Det som är enklast är troligast att ändra name-egenskapen till en const char *.

------------------
Även seriemördare är människor. http://www.choppingblock.org/
Absolut bästa episoden: http://www.choppingblock.org/d/20000925.html

UlfTMedlem sedan maj 20018 027 inlägg
#8

Chainsaw skrev:
"Det som är enklast är troligast att ändra name-egenskapen till en const char *."

Tveksamt, Tobias första exempel kommer inte fungera eftersom man inte får ändra en const-deklarerad variabel. strcpy-versionen kommer dock fungera eftersom man då ändrar i minnesutrymmen som "char *" pekar på, men där spelar det faktiskt ingen roll om "name" är deklarerad som "char *" eller "const char *".

Själv tycker jag det är bättre att deklarera "name" som en array of chars, dvs "char name[20]". Då har man försäkrat sig om att man har allokerat minne åt den strängen, i mitt exempel 20 tecken inklusive null. Men om man nu gör en tilldelning direkt till "name" så pekar den variabeln plötsligt mot ett annat minnesblock, i Tobias fall mot samma block som "_name". Det block som "name" pekade mot tidigare är fortfarande allokerat men kan nu inte nås. Därför, använd kopieringsmetoden i strcpy istället så blir allt rätt.

VetgirigMedlem sedan nov. 2000199 inlägg
#9

Om man nu nödvändigtvis vill använda sig av char* i detta fallet (titta i stället på att använda datatyper string) så bör man självklart kopiera in data från argumentet till namnet. Man bör även se till att namnet inte blir för långt.

Dvs koden bör vara:

void assign_name (const char* _name)
{
int len = strlen(_name);
if (len > NAME_MAX_LEN)
len = NAME_MAX_LEN;
name = new char[len];
strncpy(name,_name,len);
}

Med datatypen string så blir koden enklare.

Varför strncpy är att föredra framför strcpy ses varje dag i olika rapporter om att program innehåler säkerhetsproblem.
------------------
Anders Lindbäck,Igiro Internet Giro

[Redigerat av Vetgirig den 02 aug 2001]

UlfTMedlem sedan maj 20018 027 inlägg
#10

Jag måste erkänna att jag är okunnig om vilka säkerhetsproblem i strcpy som man slipper undan mha strncpy. Skulle du kunna förklara eller ge några länkar? Jag såg en dum sak med strncpy här: http://www.opengroup.org/onlinepubs/7908799/xsh/strncpy.html
man riskerar alltså att få en sträng som inte är nullterminerad om null inte ingår i de n första tecknen i källsträngen.

Problemet med datatyper string (CString, TString, QString etc.) är att de inte är någon gemensam standard som man kan räkna med alltid fungerar. Men om man vet att man bara kommer kompilera koden i en viss miljö där en viss strängtyp garanterat finns går det ju bra.

developerMedlem sedan aug. 2001458 inlägg
#11

Med strncpy kan man begränsa längden man får kopiera till destinations-pekaren, vilket minskar risken för buffer overruns. Dock kvarstår problemet att man måste hålla koll på hur mycket man får kopiera och ge som argument till strncpy.

Ett bättre sätt i mitt tycke är att använda STL-strängar, som är C++ standard. Sök på STL och string på google.com eller i MSDN.

Beträffande Chainsaws exempel om const char * håller jag med. För Chainsaw, du menade väl typ:

<font size="1" face="Verdana, Arial, Helvetica, sans-serif">Kod:<font size="1" face="Verdana, Arial, Helvetica, sans-serif" color="#666600">void assign_name (const char* _name) : name(_name)
{
}
...
private :
const char* name;
...

i main:

Person p1;
p1.assign_name("Kalle Kula");

137 ms totalt · 3 externa anrop · v20260731065814-full.16f3d68c
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
134 ms — hämta tråd, inlägg och bilagor (db)