Permalänk
Medlem

programmering stack overflow c#

Hej!

Jag har suttit och försökt lösa detta hela eftermiddagen, har kodat om allt 1 gång osv. Men när jag testkör programmet står det enbart "stack overflow". Kan någon försöka hjälpa mig förstå varför och hur jag ska lösa det?

Vore evigt tacksam!

using System; using System.Collections.Generic; // katalog för att ha möjlighet att sortera vektorn namespace jagblirgalen { namespace candycrate { public class Candy // klass för godiset { private string namn; // objekt som håller namn, sort och pris på godiset private string sort; private string kostnad; public string Namn { get { return namn; } set { namn = value; } } public string Sort { get { return sort; } set { sort = value; } } public double Kostnad { get { return Kostnad; } set { Kostnad = value; } } public Candy(string _namn, string _typ, double _kostnad) // Konstruktor för en godis { namn = _namn; // innehåller namn sort = sort; // innehåller typ Kostnad = _kostnad; // innehåller pris } } class Candycrate { private Candy[] candys = new Candy[24]; // Vektor som tar hand om Candy objekten private List<Candy> candy_list = new List<Candy>(); // Meny/lista över alla godissorter public void content_list() // Metod som fyller produktmenyn med få alternativ av sorter { candy_list.Add(new Candy("Dumle orginal", "Choklad", 0.50)); candy_list.Add(new Candy("Japp mini", "Choklad", 0.50)); candy_list.Add(new Candy("Marabou mini", "Choklad", 1.50)); candy_list.Add(new Candy("Sur patron", "Surt godis", 1.25)); candy_list.Add(new Candy("Sura bläckfiskar", "Surt godis", 0.75)); candy_list.Add(new Candy("Dödskalle Hallon", "Surt godis", 1.00)); candy_list.Add(new Candy("Salt fisk", "Lakrits", 1.25)); candy_list.Add(new Candy("Djungelvrål", "Lakrits", 0.50)); candy_list.Add(new Candy("Hallonsalta karameller", "Lakrits", 2.50)); candy_list.Add(new Candy("Gelehallon", "Sockerfritt godis", 3.75)); candy_list.Add(new Candy(" Hallon/lakritsskalle", "Sockerfritt godis", 4.25)); candy_list.Add(new Candy(" colaflaskor", "Sockerfritt godis", 4.00)); } public void stats() // metod som visar uppdaterad info om godispåsen { Console.Clear(); //används för att tömma menyn och göra rent. Console.WriteLine("\n Godispåse-stimulatorn:"); Console.WriteLine(" Antal godisar i påsen [{0}/[24] total pris: {1:0.00}kronor", RecursiveBites(0), calc_total()); if (RecursiveBites(0) == 24) Console.WriteLine("Godispåsen är nu fylld!"); // Om användaren lagt till 24 bitar i påsen else Console.WriteLine(""); } public int RecursiveBites(int index) // Rekursiv algoritm som räknar hur många godispåsar som finns i påsen { int antal = index < 24 && candys[index] == null ? RecursiveBites(index + 1) : index < 24 && candys[index] != null ? +1 + RecursiveBites(index + 1) : +0; return antal; // kollar om ett antagande de e sant eller falskt, och sker en sak beroende på resultat. } public void Run() // metod för huvudmenyn { string val; do // loopar menyn så programmet fortsätter efter menyval { stats(); Console.WriteLine("\n Meny för Godispåse-simulator"); // menyn för godis simulatorn Console.WriteLine("\n Välj ditt alternativ:"); Console.WriteLine(" 1: Lägga till en godis"); Console.WriteLine(" 2: Ta bort en godis"); Console.WriteLine(" 3: Skriv ut godispåsen"); Console.WriteLine(" 4: Sök efter en godissort"); Console.WriteLine(" 5: Sortera godispåsen"); Console.WriteLine(" 0: Avsluta programmet"); val = Console.ReadLine(); switch (val) { case "1": // Val som anropar metoden add_candy add_candy(); break; case "2": // Val som anropar metoden remove_candy tabort_candy(); break; case "3": // Val som anropar metoden print_crate print_crate(); break; case "4": // Val som anropar metoden find_candy find_candy(); break; case "5": // Val som anropar metoden sort_candy sort_candys(); break; case "0": // Val avslutar programmet break; } } while (val != "0"); //loopets villkor } public void add_candy() // metod för att kunna lägga till godis i godispåsen { Random slumpmässigt = new Random(); // gör så att man få en slumpmässigt utvald godisbit string str; do { stats(); Console.WriteLine("\n Meny: Lägg till godis"); // Skriver ut meny för add_candy Console.WriteLine("\n {0,-17} {1,-15} {2,6}\n", "Namn:", "Sort:", "Pris:"); int str_index = 1; // heltal för att listan ska få ett synligt index foreach (var candy in candy_list) { string formatString = String.Format(" {3,2}: {0,-18} {1,-15} {2,5:0.00}kronor", candy.Namn, candy.Sort, candy.Kostnad, str_index++); } Console.WriteLine("\n [S]ortera godislistan"); Console.WriteLine(" [L]ägg till ny godissort i påsen"); Console.WriteLine(" [P]acka godispåsen full"); Console.WriteLine(" [G]å till huvudmenyn"); Console.WriteLine("\n Välj godis med index att fylla påsen med"); str = Console.ReadLine(); // läser användarens svar int val = check(str); // Svaret kontrolleras if (val != -1 && val < 25 && val > 0) // Lägger till godis ifall svaret är korrekt { for (int i = 0; i < candys.Length; i++) // vektorn loopar efter den första lediga plats { if (candys[i] == null) { val--; candys[i] = candy_list[val]; // vid tom plats i systemet fylls den med godis break; } else if (i == candys.Length - 1) // vid ingen ledig plats är påsen full { Run(); } } } else { if (str == "s" || str == "S") // hoppar till sortera lista metoden sort_list(); else if (str == "l" || str == "L") { stats(); Console.WriteLine("\n Skriv in namn, sort och pris på den nya godisen, skriv in 'Avsluta' för avbryt"); Console.Write(" Namn: "); string namn = Console.ReadLine(); if (namn == "Avsluta") // vill användaren avbryta så kommer programmet gå tillbaka till metoden där man lägger till godis break; else { Console.Write(" Sort: "); string sort = Console.ReadLine(); Console.Write(" Pris: "); double pris = -1; try { string temp = Console.ReadLine(); // kontrollerar så svaret är korrekt pris = Convert.ToDouble(temp); } catch { pris = -1; } if (pris != -1) { candy_list.Add(new Candy(namn, sort, pris)); // ifall allt stämmer, så läggs den nya skapade godisen i listan Console.Clear(); // används för att hålla fönstret rent och snyggt } } } else if (str == "p" || str == "P") // val som ska fylla påsen med varierade godisar { for (int i = 0; i < candys.Length; i++) // vektorn loopar { if (candys[i] == null) // fylls på enbart där de inte finns något { int rnd = slumpmässigt.Next(1, candy_list.Count); /* Skapar en okänd siffra mellan alternativen på godislistan * så godisbitar man adderar i listan även dem kommer slumpas fram*/ candys[i] = candy_list[rnd]; } } break; } else if (str == "g" || str == "G") // användaren kommer tillbaka till "huvud"-menyn break; } } while (str != "g" || str != "G"); } public void sort_list() // metod för att kunna sortera listan { stats(); string val; Console.WriteLine(" \n Sortera menyn: "); Console.WriteLine("\n Sortera enligt: "); Console.WriteLine(" [N]amn"); Console.WriteLine(" [S]ort"); Console.WriteLine(" [P]ris"); Console.WriteLine(" [G]å till menyn"); val = Console.ReadLine(); // användaren väljer sitt val för sorteringen if (val == "n" || val == "N") { candy_list.Sort((x, y) => x == null ? 1 : y == null ? -1 : x.Namn.CompareTo(y.Namn)); // väljer användaren detta så sorteras menyn enligt namn } else if (val == "s" || val == "S") { candy_list.Sort((x, y) => x == null ? 1 : y == null ? -1 : x.Sort.CompareTo(y.Sort)); // listan sorteras enligt sorter } else if (val == "p" || val == "P") { candy_list.Sort((x, y) => x == null ? 1 : y == null ? -1 : x.Kostnad.CompareTo(y.Kostnad)); // listan sorteras enligt pris } else if (val == "g" || val == "G") // användaren tas tillbaka till menyn { Run(); } else { sort_list(); // om icke korrekt inmatning } } public void tabort_candy() // metod för att ta bort godis ur godissimulatorn/godispåsen { do // loopar borttagningen tills användaren avbryter { stats(); Console.WriteLine("\n Ta bort godis"); int num = 1; Console.WriteLine("\n {0,-17} {1,-13} {2,6}\n", "Namn:", "Sort:", "Pris:"); foreach (var candy in candys) // visar först vad som finns i påsen { if (candy != null) { string formatString = String.Format(" {3,2}: {0,-18} {1,-13} {2,5:0.00}kronor", candy.Namn, candy.Sort, candy.Kostnad, num++); } else // och till sist, allt utan innehåll { string formatString = String.Format(" {1,2}: {0}", "Ledig plats", num++); } } Console.WriteLine("\n [R]ensa listan"); // meny där man kan välja mellan att ta bort en godis i taget eller hela godispåsen.// Console.WriteLine(" [G]å till menyn"); Console.Write("\n Välj index att ta bort:"); string str = Console.ReadLine(); // användaren väljer "index att ta bort" if (str == "r" || str == "R") // val för att rensa godispåsen (vektorn) { for (int i = 0; i < candys.Length; i++) if (candys[i] != null) candys[i] = null; } else if (str == "g" || str == "G") // avbryter loopen och användaren kommer till menyn break; else { int index = check(str); // kontrollerar val if (index > 0 && index <= candys.Length) { index--; // gör så man kommer rätt i vektorn då den startar vid "0" candys[index] = null; } } } while (true); } public void print_crate() { stats(); Console.WriteLine("\n Innehåll i godispåsen"); int num = 1; Console.WriteLine("\n {0,-17} {1,-15} {2,6}\n", "Namn:", "Sort:", "Pris:"); foreach (var candy in candys) // loop som skriver ut påsens innehåll { if (candy != null) // objekt främst { string formatString = string.Format("{3,2}: {0,-18} {1,-15} {2,5:0.00}kronor", candy.Namn, candy.Sort, candy.Kostnad, num++); } else // sist kommer lediga platser { string formatString = string.Format("{1,2}: {0}", "Ledig plats", num++); } } Console.WriteLine("\n Tryck på vilken tangent som helst för att backa till menyn...."); Console.ReadKey(); } public double calc_total() // metod som räknar ut den totala kostnaden som finns i godispåsen { double total_pris = 0; foreach (var candy in candys) if (candy != null) total_pris += candy.Kostnad; return total_pris; } public void find_candy() // metod för att kunna söka efter en specifik godis i påsen/vektorn { stats(); int index; string namn; Console.WriteLine("\n Leta efter specifik godis"); Console.WriteLine("\n Skriv in namnet på godisen:"); namn = Console.ReadLine(); // användaren skriver in vad godisen heter index = LinearSearch(candys, namn); // anropar metoden linjär sökning if (index == -1) Console.WriteLine("\n Felaktigt namn"); // meddelar om användaren skrivit fel, eller om den inte finns i simulatorn else { Console.WriteLine("\n [0} finns, vill du:", candys[index].Namn); /* finns godisen så kan användaren välja vad * man vill göra när man hittat godisen*/ Console.WriteLine("\n [L]ägg till hittad godis"); Console.WriteLine(" [T]a bort hittad godis"); Console.WriteLine(" [G]å till menyn"); string val = Console.ReadLine(); // användaren gör sitt val if (val == "l" || val == "L") // val som fördubblar godisen { for (int i = 0; i < candys.Length; i++) // Loopar vektorn efter första tomma plats { if (candys[i] == null) { candys[i] = candys[index]; // när en ledig plats funnts läggs fylls den på med likadana godisar break; } else if (i == candys.Length - 1) { Run(); /* Är godispåsen full är det onödigt att försöka fylla den, så * användaren kommer automatiskt till menyn*/ } } } else if (val == "t" || val == "T") { candys[index] = null; } else if (val == "g" || val == "G") { Run(); } } Console.WriteLine("\n Tryck på valfri tangent för att komma till menyn"); Console.ReadKey(); } public int LinearSearch(Candy[] candy, string key) // metod för linjär sökning { for (int i = 0; i < candy.Length; i++) // Loop för att söka efter överensstämmande sträng { if (candy[i] != null) if (candy[i].Namn == key) return i; // finns namnet returneras index } return -1; } public void sort_candys() /* metod för att organisera i godispåsen */ { stats(); string val; Console.WriteLine("\n Sortera meny:"); Console.WriteLine("\n Sortera enligt:"); Console.WriteLine(" [N]amn"); Console.WriteLine(" [S]ort"); Console.WriteLine(" [P]ris"); Console.WriteLine(" [G]å till menyn"); val = Console.ReadLine(); // användaren gör sitt val if (val == "n" || val == "N") { Array.Sort(candys, (x, y) => x == null ? 1 : y == null ? -1 : x.Namn.CompareTo(y.Namn)); // Sorterar så de som finns i lager kommer först print_crate(); } else if (val == "s" || val == "S") { Array.Sort(candys, (x, y) => x == null ? 1 : y == null ? -1 : x.Sort.CompareTo(y.Sort)); print_crate(); } else if (val == "p" || val == "P") { Array.Sort(candys, (x, y) => x == null ? 1 : y == null ? -1 : x.Kostnad.CompareTo(y.Kostnad)); print_crate(); } else if (val == "g" || val == "G") Run(); else sort_candys(); // vid inkorrekt inmatning hamnar man i menyn igen } public int check(string input) // Metod för att granska inmatning { int korrektvärde; try { korrektvärde = int.Parse(input); // vid rätt inmatning skcikas talet tillbaka konverterat till int return korrektvärde; } catch { return korrektvärde = -1; } } } class program { public static void Main(string[] args) // Main metoden { Console.Clear(); var candycrate = new Candycrate(); // candycrate objekt bildas candycrate.content_list(); // fyller listan med godis candycrate.Run(); // anropar menyn } } } }

Permalänk
Medlem

Jisses, det där orkar jag inte läsa noga. Men stack overflow tyder på att du gör för många funktionsanrop i rad, innan föregående anrop returnerat. Eftersom det finns en rekursiv metod inblandad så är det där man bör börja titta tycker jag.

int antal = index < 24 && candys[index] == null ? RecursiveBites(index + 1) : index < 24 && candys[index] != null ? +1 + RecursiveBites(index + 1) : +0;

Den här raden är otroligt otydlig och metoden anropar sig själv, så jag skulle börja där. Skriv om koden så att den blir läsbar.

candys[index] är väl alltid null för alla index i början, när stats() anropas första gången av Run()? Jag tippar därför på att den sista RecursiveBites på raden kommer att anropas till kraschen inträffar, för väldigt många index >= 24.

Det ser ut som att du även har en del problem med att dina menyval anropas av Run() och anropar Run(), men det hinner antagligen inte trigga stack overflow. Menyvalen bör returnera i stället.

Standardtipset är att lära sig debuggern och stega igenom koden och inspektera variabelvärden.

Permalänk
Medlem
Skrivet av KAD:

Standardtipset är att lära sig debuggern och stega igenom koden och inspektera variabelvärden.

Håller med principiellt om det som stod innan (har inte heller läst all koden, så blir ju svårt att sätta fingret på exakta felet), men just detta tips är ju det enskilt viktigaste för att själv kunna felsöka på ett vettigt sätt.

Visa signatur

Desktop: Ryzen 5800X3D || MSI X570S Edge Max Wifi || Sapphire Pulse RX 7900 XTX || Gskill Trident Z 3600 64GB || Kingston KC3000 2TB || Samsung 970 EVO Plus 2TB || Samsung 960 Pro 1TB || Fractal Torrent || Asus PG42UQ 4K OLED
Proxmox server: Ryzen 5900X || Asrock Rack X570D4I-2T || Kingston 64GB ECC || WD Red SN700 1TB || Blandning av WD Red / Seagate Ironwolf för lagring || Fractal Node 304

Permalänk
Medlem

Ser ut som du bara kopierat kodblock från 10 olika lösningar och klistrat in i en. Kodstandarden ser helt olika ut mellan olika metoder. Exceptionet sker då du har en rekursiv metod som nästlar i för många anrop, hamnar alltså i en oändlig loop/rekursion.

Vad går uppgiften ut på? Känns som du har krånglat till det mycket.

Permalänk
Medlem
Skrivet av zaibuf:

Ser ut som du bara kopierat kodblock från 10 olika lösningar och klistrat in i en. Kodstandarden ser helt olika ut mellan olika metoder.

Som vilken PR som helst från juniorgänget.

Permalänk
Medlem

Stackoverflow får du när det inte finns någon exit-condition, dvs det blir en evig loop.

För att hitta snabbt: sätt en breakpoint vid alla return-satser och spamma f5.

Det kan förståss bli en stackoverflow för att minnet på riktigt blir fullt pga att det är för mycket data att bearbeta, men det är sällsynt.

Permalänk
Medlem
Skrivet av Oernfan:

Stackoverflow får du när det inte finns någon exit-condition, dvs det blir en evig loop.

För att hitta snabbt: sätt en breakpoint vid alla return-satser och spamma f5.

Det kan förståss bli en stackoverflow för att minnet på riktigt blir fullt pga att det är för mycket data att bearbeta, men det är sällsynt.

Inte vilken loop som helst, dock. Du kan ju ha en oändlig vanlig loop, men det innebär inte att stack overflow blir ett problem. Även om denna loop skulle vara ett misstag (inte nödvändigtvis fallet) så medför den ju bara att programmet "fastnar" i att fortsätta att göra samma saker för alltid, det blir inget stack overflow av det.

Det som däremot leder till stack overflow är att göra en alltför djup kedja av funktionsanrop, det är då du fyller stacken.
Ett typexempel där är då en rekursiv funktion utan slutvillkor, för där görs det ju ett funktionsanrop i varje steg som bygger på stacken.

Det blir stack overflow just precis när stacken tar slut, inte för att minnet tar slut i allmänhet. Dvs det har inget att göra med "för mycket data att bearbeta" utan helt att göra med programmets konstruktion i sig (typiskt ett direkt fel i programmets logik).

Vad gäller felsökningsstrategi så är ju en enkel variant att helt enkelt titta på callstacken när stack overflow skett, det lär ju vara mycket avslöjande angående var problemet sker. Om det är oklart hur det kan ske så är det väl lämpligt att sätta en brytpunkt i de trakterna och sedan stega sig igenom, så lär man ganska snart inse vad som är fel när man typ fortsätter att göra samma sekvens av funktionsanrop om och om igen utan att returnera.

Visa signatur

Desktop: Ryzen 5800X3D || MSI X570S Edge Max Wifi || Sapphire Pulse RX 7900 XTX || Gskill Trident Z 3600 64GB || Kingston KC3000 2TB || Samsung 970 EVO Plus 2TB || Samsung 960 Pro 1TB || Fractal Torrent || Asus PG42UQ 4K OLED
Proxmox server: Ryzen 5900X || Asrock Rack X570D4I-2T || Kingston 64GB ECC || WD Red SN700 1TB || Blandning av WD Red / Seagate Ironwolf för lagring || Fractal Node 304

Permalänk
Medlem
Skrivet av evil penguin:

Inte vilken loop som helst, dock. Du kan ju ha en oändlig vanlig loop, men det innebär inte att stack overflow blir ett problem. Även om denna loop skulle vara ett misstag (inte nödvändigtvis fallet) så medför den ju bara att programmet "fastnar" i att fortsätta att göra samma saker för alltid, det blir inget stack overflow av det.

Det som däremot leder till stack overflow är att göra en alltför djup kedja av funktionsanrop, det är då du fyller stacken.
Ett typexempel där är då en rekursiv funktion utan slutvillkor, för där görs det ju ett funktionsanrop i varje steg som bygger på stacken.

Det blir stack overflow just precis när stacken tar slut, inte för att minnet tar slut i allmänhet. Dvs det har inget att göra med "för mycket data att bearbeta" utan helt att göra med programmets konstruktion i sig (typiskt ett direkt fel i programmets logik).

Vad gäller felsökningsstrategi så är ju en enkel variant att helt enkelt titta på callstacken när stack overflow skett, det lär ju vara mycket avslöjande angående var problemet sker. Om det är oklart hur det kan ske så är det väl lämpligt att sätta en brytpunkt i de trakterna och sedan stega sig igenom, så lär man ganska snart inse vad som är fel när man typ fortsätter att göra samma sekvens av funktionsanrop om och om igen utan att returnera.

Det vanligaste är som sagt rekursion, men det går att få stackoverflow om man t.ex. deklarerar en jättestor lokal variabel. Ex i C: char myArray[100000000];
Denna skulle hamna på heap i C# och således inte leda till stackoverflow.