Fetstil Fetstil Kursiv Understrykning linje färgläggning tabellverk Punktlista Nummerlista Vänster Centrerat högerställt Utfyllt Länk Bild htmlmode
  • Forum & Blog
    • Forum - översikt
      • .Net
        • asp.net generellt
        • c#
        • vb.net
        • f#
        • silverlight
        • microsoft surface
        • visual studio .net
      • databaser
        • sql-server
        • databaser
        • access
        • mysql
      • mjukvara klient
        • datorer och komponenter
        • nätverk, lan/wan
        • operativsystem
        • programvaror
        • säkerhet, inställningar
        • windows server
        • allmänt
        • crystal reports
        • exchange/outlook
        • microsoft office
      • mjukvara server
        • active directory
        • biztalk
        • exchange
        • linux
        • sharepoint
        • webbservers
        • sql server
      • appar (win/mobil)
      • programspråk
        • c++
        • delphi
        • java
        • quick basic
        • visual basic
      • scripting
        • asp 3.0
        • flash actionscript
        • html css
        • javascript
        • php
        • regular expresssion
        • xml
      • spel och grafik
        • DirectX
        • Spel och grafik
      • ledning
        • Arkitektur
        • Systemutveckling
        • krav och test
        • projektledning
        • ledningsfrågor
      • vb-sektioner
        • activeX
        • windows api
        • elektronik
        • internet
        • komponenter
        • nätverk
        • operativsystem
      • övriga forum
        • arbete karriär
        • erbjuda uppdrag och tjänster
        • juridiska frågor
        • köp och sälj
        • matematik och fysik
        • intern information
        • skrivklåda
        • webb-operatörer
    • Posta inlägg i forumet
    • Chatta med andra
  • Konto
    • Medlemssida
    • Byta lösenord
    • Bli bonsumedlem
    • iMail
  • Material
    • Tips & tricks
    • Artiklar
    • Programarkiv
  • JOBB
  • Student
    • Studentlicenser
  • KONTAKT
    • Om pellesoft
    • Grundare
    • Kontakta oss
    • Annonsering
    • Partners
    • Felanmälan
  • Logga in

Hem / Forum översikt / inlägg

Posta nytt inlägg


Skriva på sträng

Postades av 2005-01-14 16:31:57 - Pablo Zendejas, i forum c++, Tråden har 31 Kommentarer och lästs av 1141 personer

Denna funktion genererar ett segmentation error. Den ska bara ta en sträng, stympa den och skriva ut bitarna med andra strängar emellan bitarna. Kanske lite dåligt förklarat men koden är rätt så simpel. Jag har fått liknande kod att fungera, säg till om jag ska posta den. Jag sitter på en Debian Sarge (Linux) och kompilerar med GCC men jag tror inte att Windows skiljer sig från Linux i detta fallet.

#include <string>
#include <iostream>
void print(char string[], char *strings[], int argc){
     int i;
     char * pointer_1, * pointer_2;
     pointer_1=&string[0];
     while(i<argc){
	     pointer_2 = strstr (pointer_1,"dd"); //Hittar "dd" i strängen och sätter en pekare att peka dit
	     if(pointer_2==NULL){
		     cout<<"null!!"<<endl;
	             break;
	     }
	     strncpy(pointer_2,"\0\0",2); // <------ Denna rad generar ett segmentation error. 
	     cout<<pointer_1<<endl<<endl; //Skriver ut 
	     cout<<strings[i]<<endl; 
	     pointer_1=pointer_2+2; //Sätt pekare "pointer_1" att peka på nästa bit av strängen
             i++;
     }
     
  } 


Svara

Sv: Skriva på sträng

Postades av 2005-01-14 17:07:09 - Niklas Jansson

Hmm... den där koden ser inget vidare ut.
Grejen är det här:
1. Du inkluderar fel header.
#include <string>
innebär att du inkluderar string. string är C++-biblioteket för klassen string. Det du använder i koden är dock c-strängar, så om något bör du inkludera <cstring>. Till detta kommer namespace också.

2. Du kör med C-strängar i onödan. Använd hellre <string> tillsammans med C++-strängarna "string" och C++-arrayerna "vector". Slipper du bry dig om minneshantering etc.

3. Du kallar strängarna för string, det är dumt när det redan finns klasser som heter det, etc.

Nåväl, om du inte väljer att gå över till det väsentligt mycket bättre standardbiblioteket (snabbare, snyggare, enklare, mindre resurskrävande) så ser jag nog bara att du använder "\0\0", vilket ju i praktiken blir tre stycken \0.
Använd hellre *pointer_2=0; *(pointer_2+1)=0; eller något liknande i så fall.


Svara

Sv:Skriva på sträng

Postades av 2005-01-14 19:31:46 - Pablo Zendejas

Alla funktionerna (strncopy, strstr) som jag använder finns ju i string.

Jag VILL lära mig c-strängar! :P

strcopy kopierar bara över så många tecken som jag anger, i detta exemplet 2. Det lägger inte till ett sista '\0' efter tecknen.

*pointer_2=0; *(pointer_2+1)=0; fungerade inte, får ändå segmentation error

Den här koden fungerar utan problem:

int main ()
{
  char str[] ="hej dd da";
  char * pointer;
  pointer = strstr (str,"dd");
  strncpy (pointer,"\0\0",2);
  cout<<str<<endl;
  cout<<(pointer+2)<<endl;
  return 0;
}

och den fungerar ju nästan likadant, eller?


Svara

Sv: Skriva på sträng

Postades av 2005-01-14 20:36:01 - Per Persson

Finns det tillräckligt med utrymme i string för att få plats med allt?


Svara

Sv:Skriva på sträng

Postades av 2005-01-14 20:40:36 - Pablo Zendejas

Så vitt jag förstår så skriver strncopy bara över "dd" med "\0\0", så ingen mera plats behövs.

Segmentation error är väl när man går utanför sina egna data och börjar skriva (eller läsa?) på platser som man inte allokerat? Eller?


Svara

Sv: Skriva på sträng

Postades av 2005-01-14 22:43:18 - Martin Adrian

Vad är det för sträng du skickar in?

Om det är en konstant sträng t.ex. "abcdd" så kan du få ett segmentation fault om compilatorn placerat strängen i read-only-memory.

Skillnaden mot det andra exemplet är att där kan inte kompilatorn placera strängen i read-only-memory eftersom den tilldelas till en icke-const variabel.

Jämför följande:

char str[] = "blabla";
strcpy(str, "abcabc");

är ok medan
strcpy("blabla", "abcabc");

är "undefined behaviour" (t.ex segmentation fault)

Du borde dock ha fått en varning vid funktionsanropet?


Svara

Sv:Skriva på sträng

Postades av 2005-01-15 11:53:29 - Pablo Zendejas

Programmet kompilerar... :(
Jag har även provat att skapa en ny sträng i funktionen och kopiera över strängen dit, men jag får ändå segmentation error när jag skriver över med "\0\0".


Svara

Sv: Skriva på sträng

Postades av 2005-01-15 12:21:34 - Per Persson

Hur ser anropet av print() ut?


Svara

Sv: Skriva på sträng

Postades av 2005-01-15 14:36:13 - Håkan Borneland

Hej!

Orsaken till felet är att du inte initsierat vaiabeln "i" till något.
Programmet får svårt att utvärdera den, när det ska in i while loopen.

//Håkan




Svara

Sv:Skriva på sträng

Postades av 2005-01-15 17:22:50 - Niklas Jansson

<b>>Alla funktionerna (strncopy, strstr) som jag använder finns ju i string.</b>
Måhända är jag helt snurrig nu, men vad jag vet så skall alla moderna kompilatorer ha sina c-strängfunktioner i <cstring> och alla sina vanliga i <string>. Den gamla <string.h> är jag osäker på vilken det motsvarar.

<b>>Jag VILL lära mig c-strängar! :P</b>
Kan jag gå med på, men ett starkt råd är verkligen att undvika dem. Det finns i princip bara ett enda tillfälle när man måste eller ens bör använda dem, och det är när man har någon äldre funktion som returnerar eller kräver en c-sträng.

<b>>Orsaken till felet är att du inte initsierat vaiabeln "i" till något.</b>
Där var det!
Kombination av att varken i eller pointer_2 var initierad är felet.


Svara

Sv: Skriva på sträng

Postades av 2005-01-15 18:53:45 - Per Persson

<b>Måhända är jag helt snurrig nu, men vad jag vet så skall alla moderna kompilatorer ha sina c-strängfunktioner i <cstring> och alla sina vanliga i <string>. Den gamla <string.h> är jag osäker på vilken det motsvarar.</b>

De "gamla" headerfilerna för C har i C++ fått ett c tillagt i början av namnet samtidigt som man skippar ändelsen. Så string.h har blivit cstring.

Men om man inte behöver något som definieras i en headerfil, behöver man inte nödvändigtvis inkludera filen. Vanliga deklarationer kan man oftast skippa. Själva funktionerna ligger i binärfiler och länkas in ändå. Därför fungerar koden utan att #include <cstring> används.


Svara

Sv:Skriva på sträng

Postades av 2005-01-15 20:21:45 - Pablo Zendejas

Jag ändrade på koden och lade in:

int i=0;

och
pointer_2=NULL;

innan loopen men jag får fortfarande segmentation error av den där strncpy();. Jag provade att lägga koden utanför loopen men det fungerade ändå inte, strncpy(); ger ändå fel :(.

Anropet till print() ser ut så här.
char *strings[4]={ "ETT", "TVA", "TRE" };
out.print("hej dd what's dd up? dd ",strings,3);

print() är en metod som ni ser, men det borde väl inte spela någon roll i detta fallet...

Tack för ert tålamod :P.


Svara

Sv: Skriva på sträng

Postades av 2005-01-15 21:01:25 - Per Persson

Läs Martin Adrians inlägg ovan:
<b>Om det är en konstant sträng t.ex. "abcdd" så kan du få ett segmentation fault om compilatorn placerat strängen i read-only-memory.</b>


Svara

Sv: Skriva på sträng

Postades av 2005-01-16 00:24:57 - Håkan Borneland

Hej!

Felet uppstår när du i anropet till strncpy anger att du ska kopiera 2 tecken.
"\0\0" är nämligen lika med 0.
För att det ska fungera med koden du har nu får du skriva:

strncpy( pointer_2 , "\0\0", 0 );

Å andra sidan kan du remma raden helt, den gör inget vettigt ändå.

//Håkan


Svara

Sv:Skriva på sträng

Postades av 2005-01-16 02:02:00 - Per Persson

<b>Felet uppstår när du i anropet till strncpy anger att du ska kopiera 2 tecken.</b>
Varför skulle det där leda till "segmentation fault"?


Svara

Sv: Skriva på sträng

Postades av 2005-01-16 02:19:53 - Håkan Borneland

Jaaa du...

Det beror på strncpy, den försöker kopiera det antal bytes som angivits, som inte "finns".
M.a.o läsa minne som inte finns allokerat.
Första raden i assemblerkoden läser från "\0\0" och lägger i A1.
Här smäller det i assemblerkoden (sista raden).
<code>
mov al,byte ptr [esi] ; load byte from source
add esi,1
mov [edi],al ; store byte to dest
</code>

//Håkan


Svara

Sv:Skriva på sträng

Postades av 2005-01-16 11:36:56 - Martin Adrian

strncpy kopierar bara fram till första '\0' dock max "n" tecken. Eftersom strängen som skall kopieras ("\0\0") är tom (första tecknet är '\0') så kopierar strncpy bara ett tecken. Hävdar fortfarande att krashen beror på att kompilatorn placerat strängen i ett read-only segment. Förstår dock inte varför kompilatorn inte ger en varning vid anropet av print (conversion from "const char[]" to "char*")


Svara

Sv:Skriva på sträng

Postades av 2005-01-16 12:05:34 - Per Persson

<b>Det beror på strncpy, den försöker kopiera det antal bytes som angivits, som inte "finns".</b>

Vad då 'inte "finns"'? Nolltecknena finns ju.


Svara

Sv: Skriva på sträng

Postades av 2005-01-16 12:22:50 - Håkan Borneland

Hej!

Justering: Det är char pekaren som är problemet (har inte har en riktig null terminering? antar jag).
strncpy vill ha en char[] som argument, då fungerar det (null terminering).
Här blir det noga med längden på char[], och längden på data som ska tilldelas/kopieras.
Samt med nulltermineringen.
Vet inte riktigt vad ett read-only segment (processorn?) skulle vara i det här fallet,
och i så fall varför den (kompilatorn) skulle placera den där.
Förklara gärna, kul med ny kunskap.
//Håkan


Svara

Sv: Skriva på sträng

Postades av 2005-01-16 12:28:00 - Håkan Borneland

<b>>Vad då 'inte "finns"'? Nolltecknena finns ju.</b>

Ja finns, men "räknas" inte.."
Många (alla??) (cstring) strängfunktioner bortser från nulltecknet.
Rätta mig, jag har haft fel förut.. :-)

//Håkan


Svara

Sv:Skriva på sträng

Postades av 2005-01-16 12:43:46 - Niklas Jansson

<b>>Vet inte riktigt vad ett read-only segment (processorn?) skulle vara i det här fallet, </b>

Alltså, om du har en konstant sträng, typ const char[]="arne", så är den readonly (i princip). I vissa fall går det att ändra den ändå, men den ska inte kunna ändras.

Om du använder en literal, typ 3, NULL, eller "arne", så ligger de i en speciell minnesarea som programmet inte kan ändra. Hade alltså argumentet varit en "riktig" sträng, med motsvarande sträng tilldelad, hade det fungerat. typ char * sträng= "lång mening"

Fast som sagt. Allt det här hade lätt kunnat undvikas om man hade använt de mångfaldigt bättre funktionerna och klasserna från C++.


Svara

Sv: Skriva på sträng

Postades av 2005-01-16 13:08:01 - Håkan Borneland

<b>>Alltså, om du har en konstant sträng, typ const char[]="arne", så är den readonly (i princip)</b>

Är helt med på const och vad det innebär.
Om det är const som avses, så är det uttrycket read-only segment som dribblade bort mig.
Har aldrig hört/läst det så, men som jag skrev ovan, kul med nya kunskaper.

//Håkan


Svara

Sv:Skriva på sträng

Postades av 2005-01-16 13:22:54 - Håkan Borneland

tillbaka till frågan.
Den enda const deklarationen jag vet som är aktuell i det här fallet, är andra argumentet till strncpy.
Vilket då blir "\0\0".
Detta för att strncpy inte ska ändra på argumentet (som Niklas skrev ovan).
(sparkar in öppna dörrar ;-) ).
Om nu const (read-only) deklarationen är ett problem borde den ju aldrig fungera, eller....??
Däremot om man tillhanda håller en char[] (med nullterminering) som första argument så fungerar det.
D.v.s. med "\0\0" och 2 som andra och tredje argument.
Det borde inte fungera om const är problemet, eller...??

//Håkan


Svara

Sv: Skriva på sträng

Postades av 2005-01-16 13:42:48 - Niklas Jansson

Vi kan för tillfället säga så här: alla konstanter är lika konstanta. Alltså säger vi att alla const ... eller alla literaler, etc. ligger på ett låst område av minnet som man inte har tillgång till.

Ok, då får vi aldrig ändra en literal eller en konstant, för då får vi ett fel. Det vill säga att vi kan inte göra så här:

const char * str="Martin";
str="Göran"; //fel!
"Lasse"="Göran"; //lika fel!
strncpy(str, "Göran", 5); //lika fel!
strncpy("Lasse", "Göran", 5); //lika fel!


Det som i praktiken sker i programmet är sista varianten, man försöker använda strncpy på en literal. Vad som står i andra argumentet spelar ingen roll, och att "\0\0" är konstant ger alltså ingen skillnad.
Däremot är anropet till print med en literal felaktig.

Edit:
Anropet bör alltså se ut något sånt här;
char *strings[4]={ "ETT", "TVA", "TRE" };
char *string="hej dd what's dd up? dd ";
out.print(string, strings, 3);


Men som sagt så hade det här varit busenkelt om man hade använt C++ på rätt sätt. Det är synd att folk inte ger sig på att använda det ordentligt.


Svara

Sv:Skriva på sträng

Postades av 2005-01-16 15:11:07 - Pablo Zendejas

Jag får tacka så mycket, med:

char *strings[4]={ "ETT", "TVA", "TRE" };
char string[]="hej dd what's dd up? dd ";
out.print(string, strings, 3);

fungerar allting perfekt :).

Jag har också lärt mig rätt så mycket av den här tråden :D.

Anledningen till att jag vill lära mig att hålla på med c-strängar är att jag vill veta vad som pågår "under huven" och kunna hålla på med lågnivåprogrammering där det inte finns bibliotek som <string>, det är något av en "dröm" :P.

Tack så mycket.
/Pablo


Svara

Sv:Skriva på sträng

Postades av 2005-01-16 16:21:22 - Martin Adrian

>Vet inte riktigt vad ett read-only segment (processorn?) skulle vara i det här fallet,
>och i så fall varför den (kompilatorn) skulle placera den där.
>Förklara gärna, kul med ny kunskap.

Varje del av minnet (segment) som en process använder har vissa egenskaper (I det här fallet menar jag logiska egenskaper inte fysiska). Windows sätter attribut som beskriver egenskaperna och sen ser hårdvaran i processorn till att de efterlevs.
Attributen är:
1. Read - processen får läsa i det här minnet
2. Write - processen får skriva i det här minnet
3. Execute - processen för köra program i det här minnet
Sen finns det några andra varianter som har med det virtuella minnet att göra (tex om ett visst minnessegment just nu finns i datorns internminne eller på hårddisken)

Hur fördelas då minnet när man laddar ett program:
1. Själva programkoden får såklart attributet "Execute" så att programmet kan köras. Vanligtvis får det också attributet "Read" eftersom kompilatorer ofta lägger konstanter tillsammans med koden (strängen som diskuteras i den här tråden är ett bra exempel). Dock får processen inte skriva över sin egen programkod och därför får segmentet inte attributet "write" (vilket ger segmentation fault om man försöker). Förr (80-talet) var det populärt att använda självmodiferande kod eftersom det var snabbare men nuförtiden är det nog bara virus som använder sig av det för att försvåra upptäckt.

2. Variabler och stack för programmet får naturligtvis attributen "read" & "write" men inte "execute". Detta innebär att du inte kan stoppa in assemblerkod i en variabel och sedan köra den koden. Detta används främst av virus genom s.k. buffer overrun. Problemet här har varit att hårdvaran i de flesta CPU:er inte kollar "execute" attributet så buffer-overrun fungerar iallafall. AMD64 (och troligen andra nyare CPU:er) har denna funktion. Ni har väl hört reklamen om AMD64:s inbyggda virusskydd. Nu vet ni vad det är också.


Svara

Sv: Skriva på sträng

Postades av 2005-01-16 17:22:34 - Per Persson

<b>Ni har väl hört reklamen om AMD64:s inbyggda virusskydd. Nu vet ni vad det är också.</b>

De har fått kritik för falsk marknadsföring eftersom processorn egentligen inte innehåller ett generellt "virusskydd" utan bara skyddar mot vissa typer av virus.


Kort sammanfattning av orsaken till kraschen:
Den sträng som Pablo försökte skriva i låg i skrivskyddat minne.


Svara

Sv: Skriva på sträng

Postades av 2005-01-16 18:55:46 - Håkan Borneland

Hej igen!

Kul att det här forumet lever upp lite grand.
Tack för din förklaring.

void print( char string[], char* strings[], int argc )
{
    int i = 0;
	char strarr[40];
	char* pointer_2 = NULL;

	strncpy( strarr , string, strlen( string ) );

    while( i  < argc )
	{
        pointer_2 = strstr( strarr, "dd" ); //Hittar "dd" i strängen och sätter en pekare att peka dit

        if( pointer_2 == NULL )
		{
            printf( "null!!\n" );
            break;
        }
 		strncpy( pointer_2 , "\0\0", 2 ); // <------ Denna rad generar ett segmentation error. 
        printf( "%s\n\n", strarr ); //Skriver ut 
        printf( "%s\n", strings[i] ); 
        strncpy( strarr , &*( pointer_2 + 2 ),  40 );  
        i++;
       }
} 

int main()
{
	char* strings[4] = { "ETT", "TVA", "TRE" };
	print( "hej dd what's dd up? dd ", strings, 3 );

	return 0;
}

Bifogar ovanstående (fungerande) kod för provkörning/granskning.
Det är samma kod som Pablo hade, MEN jag har bytt ut pointer_1 mot en char[40].
Detta för att få kontroll (som jag skrev ovan) på strängen (nulltermineringen eg. längden data).
Nu fungerar anropet:
print( "hej dd what's dd up? dd ", strings, 3 );

Pekar bara på att det inte har med anropet (enbart) av print att göra.
Det spelar roll vad som händer sedan också.
OBS detta bara för att vidare belysa/diskutera.
Kul med lite liv i C++ forumet... :-)
Pablo lär sig saker och jag med.

//Håkan


Svara

Sv:Skriva på sträng

Postades av 2005-01-16 19:05:48 - Martin Adrian

const char * str="Martin";
str="Göran"; //fel!

Detta är inget fel. "str" är en variabel som innehåller en pekare till en konstant men variabeln isig är inte konstant
utan kan ändras.
const char* str="Martin";
*str = 'x'; // fel: str innehåller en pekare till en konstant 
str = "Göran"; // ok: str innehåller nu en pekare till en annan konstant
char* str1 = "Lasse";
str1 = str; // fel: str1 måste innehålla en pekare till icke-konstant.
const char* str2 = str1; // ok: pekare till konstanter kan också peka på icke-konstanter.
*str2 = 'x'; //fel: str2 ineehåller en pekare till en konstant (spelar ingen roll att det inte är en verklig konstant)
*const_cast<char*>(str2) = 'x'; // ok: ta bort const eftersom str2 inte pekar på en verklig konstant.
*const_cast<char*>(str1) = 'x'; // undefined behaviour (t.ex. segmentation fault) eftersom str1 pekar på en verklig konstant.

För att göra variabeln str konstant så att den inte kan ändras
const char* const str = "Martin";
str = "Göran"; // fel!


<code>
"Lasse"="Göran"; //lika fel!
</code>
lika fel som vaddå? Anledningen till att ovanstående inte fungerar har inget med const att göra. Det fungerar inte eftersom "Lasse" inte är en variabel och således inte kan tilldelas ett värde.


Svara

Sv: Skriva på sträng

Postades av 2005-01-17 00:06:40 - Håkan Borneland

Bra förklaring, Martin.

//Håkan


Svara

Sv: Skriva på sträng

Postades av 2005-01-17 01:04:40 - Per Persson

Man kan även ha pekarvariabler som inte får ändras, men det som de pekar på får ändras:

char mar[] = "Martin";
char* const str = mar;
*str = 'P';  // ok: det str pekar på får ändras
str = "Göran"; // fel! str får inte ändras


Svara

Sv:Skriva på sträng

Postades av 2005-01-17 11:49:50 - Niklas Jansson

Jävlars, nu tänkte jag fel ändå!
Eller rättare sagt tänkte inte alls. Det är naturligtvis helt rätt som Martin säger. Man får ha koll på var man sätter sina const!

Hade det nu varit frågan om string istället så hade jag ju bara skrivit const string, och inte behövt tänka en sekund mer på det...


Svara

Nyligen

  • 21:41 Automotive Services UK
  • 20:44 Erfarenhet av CBD-olja mot sömnpro
  • 12:13 Sex Dolls for Sale
  • 19:42 Online Casinos for Haitian Players
  • 19:38 Rekommendera något intressant
  • 19:13 Международная перевозка грузов
  • 00:01 DL Van Tuning | Exclusive Body Kit
  • 12:08 Indian casino

Sidor

  • Hem
  • Bli bonusmedlem
  • Läs artiklar
  • Chatta med andra
  • Sök och erbjud jobb
  • Kontakta oss
  • Studentlicenser
  • Skriv en artikel

Statistik

Antal besökare:
Antal medlemmar:
Antal inlägg:
Online:
På chatten:
4 570 879
27 965
271 774
709
0

Kontakta oss

Frågor runt konsultation, rådgivning, uppdrag, rekrytering, annonsering och övriga ärenden. Ring: 0730-88 22 24 | pelle@pellesoft.se

© 1986-2013 PelleSoft AB. Last Build 4.1.7169.18070 (2019-08-18 10:02:21) 4.0.30319.42000
  • Om
  • Kontakta
  • Regler
  • Cookies