Beräkna värdet tills summan överstinger n (C)

Permalänk

För att få lite mer variation i uppgiften kan du googla funktionen srand()

Permalänk
Medlem
Skrivet av kwame:

Edit: hittade felet själv.... hade inte lagt till \n i första printf-satsen och då skrevs den första talföljden (6) ut bredvid 1an (16)...

#include <stdio.h> #include <stdlib.h> int main() { int array[10]; int sum = 0, medel = 0, max = 0, i; int mini = 10; int tal = 0; for(i=0; i<10; i++){ tal = rand() % 6+1; array[i] = tal; if(array[i]<mini) { mini = array[i]; } if(array[i]>max) { max = array[i]; } sum = sum+array[i]; medel = sum/10; } printf("%d %d %d %d", sum, medel, max, mini); for(i=0; i<10; i++) printf("%d\n", array[i]); }

Du behöver använda mycket bättre variabelnamn. Kodsnuttar du länkat tidigare i tråden har samma problem. Döp inte en int array variable till "array" - Det har ingen som helst betydelse. Variabelnamn ska vara namn som gör det enkelt för dig (och andra) att avläsa och förstå vad din kod gör, utan att behöva lus-läsa och testa sig fram.

Du har deklarerat en variabel int i; just i är ett variabelnamn som används i for-loopar för att kunna traversera arrayer och div. annat. Deklarera istället när du använder din for-loop. t.ex.

for (int i = 0; i < 10; i++) { }

Nu existerar din variabeln endast inuti for-loopens omfång och ingen annanstans. P.g.a att du deklarerat en temporär variabel (menad för loopar) "allra högst upp", så har du nu blockerat resten av main från att någonsin kunna använda sig av i igen. Detta är inte good practice.

Visa signatur

öh öh har den äran!

Permalänk
Medlem
Skrivet av Dumsnuten:

Du behöver använda mycket bättre variabelnamn. Kodsnuttar du länkat tidigare i tråden har samma problem. Döp inte en int array variable till "array" - Det har ingen som helst betydelse. Variabelnamn ska vara namn som gör det enkelt för dig (och andra) att avläsa och förstå vad din kod gör, utan att behöva lus-läsa och testa sig fram.

Du har deklarerat en variabel int i; just i är ett variabelnamn som används i for-loopar för att kunna traversera arrayer och div. annat. Deklarera istället när du använder din for-loop. t.ex.

for (int i = 0; i < 10; i++) { }

Nu existerar din variabeln endast inuti for-loopens omfång och ingen annanstans. P.g.a att du deklarerat en temporär variabel (menad för loopar) "allra högst upp", så har du nu blockerat resten av main från att någonsin kunna använda sig av i igen. Detta är inte good practice.

Absolut, det där var dock bara en liten tentauppgift som man skriver skriftligt på ett papper - så jag brydde mig inte särskilt mycket om struktur eller smarta namn. Men du har helt rätt, den mesta koden jag skrivit i denna tråden har inte heller varit särskilt bra strukturerad.

Här är en "seriös" kod för min första uppgift - mer eller mindre klar. Denna får du gärna granska och ge kritik på

Såg nu att du redan gett mig ett bra svar som jag kan ändra på: " for (int i = 0; i < 10; i++) { }"

#include <stdio.h> #include <stdlib.h> #include <time.h> #define ANTAL 100 #define radStart 0 #define radEnd 10 #define kolumnStart 0 #define kolumnEnd 10 #define randMax 901 void printMenu(); void mrndgen(int lista[ANTAL]); void sort(int lista[ANTAL]); void med(int lista[ANTAL]); void graph(int lista[ANTAL]); void binarsok(int lista[ANTAL]); int main() { int failsafe = 0; int lista[ANTAL]; char choice = 0; while(choice != 5) { printMenu(); // här skriver vi ut menyn i en while-loop tills villkoret inte längre är uppfyllt. scanf(" %c", &choice); switch(choice) { case '1': mrndgen(lista); failsafe = 1; break; case '2': if(failsafe == 1){sort(lista); failsafe = 2;} else printf("Du måste ha en talfoljd."); break; case '3': if(failsafe == 2) med(lista); else printf("Du maste ha en sorterad talfoljd."); break; case '4': if(failsafe == 2) binarsok(lista); else printf("Du maste ha en sorterad talfoljd."); break; default: printf("Ogiltigt val."); } } return 0; } void printMenu() // skapar en meny { printf("\n/==========================================================================/\n"); printf("/=================================MENU=====================================/\n"); printf("/==========================================================================/\n"); printf("1. Alstra en talfoljd med en slumpgenerator och skriv ut talen pa skarmen.\n"); printf("2. Sortera talfoljden med bubbelsortering. Efter sorteringen skall talfoljden skrivas ut pa skarmen.\n"); printf("3. Medelvarde, median, maxvarde och minvarde skall beraknas och skrivas ut pa skarmen.\n"); printf("4. Med binarsokning skall man kunna soka efter ett valfritt tal. Om talet finns i talfoljden meddelas, pa skarmen,\n pa vilken plats i tabellen (rad och kolumn) talet finns. Annars meddelas att talet inte finns i talfoljden.\n"); printf("/==========================================================================/\n"); printf("/==========================================================================/\n"); printf("/==========================================================================/\n"); printf(">>: \n"); } void graph(int lista[ANTAL]) // skapar en 10*10 kolumn där int y är värdena vi ska lagra. { int kolumner; int rader; int x = 0; for(rader = radStart; rader < radEnd; rader++) { for (kolumner = kolumnStart; kolumner<kolumnEnd; kolumner++){ printf("%d \t", lista[x]); x++; // x börjar på 0 och går mot 100 då dessa tillsammans kommer köras 100 gånger. } printf("\n"); } } void mrndgen(int lista[ANTAL]) // skapar en slumpartad talföljd i en array. { srand(time(NULL)); int tal = 0; for(int i=0; i<ANTAL; i++) { tal = rand() % randMax; lista[i] = tal; } graph(lista); } void sort(int lista[ANTAL]) // sorterar den slumpartade talföljden { int temp = 0; for(int i = 0; i < ANTAL-1; i++) { for(int j = 0; j < ANTAL-1-i; j++) { if(lista[j] > lista[j+1]) { temp = lista[j]; lista[j] = lista[j+1]; lista[j+1] = temp; } } } printf("Sorted list: \n"); graph(lista); } void med(int lista[ANTAL]) // Beräknar medelvärde, median,, min och max. { int sum = 0, max = 0, tal = 0, mini = 1000; float medel = 0, median = 0, median2 = 0, median1 = 0; for(int i=0; i<ANTAL; i++) { sum = sum + lista[i]; medel = sum/ANTAL; tal = lista[i]; if(tal < mini) mini = tal; if(tal > max) max = tal; } median2 = lista[50]; median1 = lista[49]; median = (median2+median1)/2; printf("The average is: %.2f, max is: %d min is: %d median is %.2f", medel, max, mini, median); } void binarsok(int lista[ANTAL]){ // Binärsökning. int v=0, h=ANTAL, mitten, sok; // v = startvärdet i arrayen upp till 100. Mitten blir alltså 100+0/2 = 50. Nästa mitt om > 50 = 100+50/2 = 75 osvosv. printf("\nAnge soktal: "); scanf("%d",&sok); while((h-v) > 1) { mitten=(v+h)/2; if(sok>=lista[mitten]) // ifall t.ex 20 >= mitten så är v (dvs 0) mitten. Och den letar då mellan 0-50 som steg 2. v=mitten; else h=mitten; // här blir 100 mitten så då letar den mellan 50-100 som steg 2. } if(sok==lista[v]) printf("Talet finns pa plats: %d\nRad: %d\nKolumn: %d\n",v+1, v/10+1, v%10+1); // Eftersom arrayen börjar på 0 och kolumnen på 1 så behöver man ta +1 för att få fram rätt. else printf("Talet finns inte i talfoljden\n"); }

Dold text
Visa signatur

10700K | NVIDIA RTX 3080

Permalänk

@kwame: Det är bra att det går framåt. Om vi nu skall börja peta i detaljer så är det lite småsaker jag vill peka på.

Du har en #define ANTAL 100 som används på nästan alla ställen. Men när du skall beräkna medianen går du direkt på 49 och 50. Det blir inte bra om du ändrar på ANTAL.

Du använder heltalsdivision till att beräkna medelvärdet. Det är lite krångliga regler för hur uttryck beräknas i C och det är lätt att det blir fel om man inte är på sin vakt. Lite förenklat kan vi säga att om (minst) en av operanderna i uttrycket har flyttalstyp kommer beräkningen göras med flyttal, annars görs den med heltal. I ditt fall kommer beräkningen ske i följande ordning: först divideras (heltalsvariabeln) sum med (heltals-)konstanten 100 och resultatet blir ett heltal (dvs. man struntar i decimalerna), sedan konverteras resultatet till ett flyttal och (flyttals-)variabeln medel tilldelas detta värde. (I median-fallet blir det rätt. Där har du mellanlandat i median1 och median2 som har flyttalstyp. Då kommer summan av det två talen vara ett flyttal. Divisionen är då ett flyttal dela med ett heltal och då måste beräkningen göras med flyttal.) För att få medelvärdesberäkningen att göras med en flyttalsoperation kan du antingen mellanlanda i en flyttalsvariabel eller helt enkelt konvertera summan till ett flyttal innan den divideras: medel = ((float)sum)/ANTAL;

Sedan är det onödigt att beräkna medelvärdet i varje varv i loopen. Den beräkningen borde ske först när du har räknat ihop alla värden.

Permalänk
Medlem
Skrivet av Ingetledigtnamn:

@kwame: Det är bra att det går framåt. Om vi nu skall börja peta i detaljer så är det lite småsaker jag vill peka på.

Du har en #define ANTAL 100 som används på nästan alla ställen. Men när du skall beräkna medianen går du direkt på 49 och 50. Det blir inte bra om du ändrar på ANTAL.

Du använder heltalsdivision till att beräkna medelvärdet. Det är lite krångliga regler för hur uttryck beräknas i C och det är lätt att det blir fel om man inte är på sin vakt. Lite förenklat kan vi säga att om (minst) en av operanderna i uttrycket har flyttalstyp kommer beräkningen göras med flyttal, annars görs den med heltal. I ditt fall kommer beräkningen ske i följande ordning: först divideras (heltalsvariabeln) sum med (heltals-)konstanten 100 och resultatet blir ett heltal (dvs. man struntar i decimalerna), sedan konverteras resultatet till ett flyttal och (flyttals-)variabeln medel tilldelas detta värde. (I median-fallet blir det rätt. Där har du mellanlandat i median1 och median2 som har flyttalstyp. Då kommer summan av det två talen vara ett flyttal. Divisionen är då ett flyttal dela med ett heltal och då måste beräkningen göras med flyttal.) För att få medelvärdesberäkningen att göras med en flyttalsoperation kan du antingen mellanlanda i en flyttalsvariabel eller helt enkelt konvertera summan till ett flyttal innan den divideras: medel = ((float)sum)/ANTAL;

Sedan är det onödigt att beräkna medelvärdet i varje varv i loopen. Den beräkningen borde ske först när du har räknat ihop alla värden.

Tack, hade ingen aning om det där med om minst en operand är av uttrycket flyttal att beräkningen då kommer göras i flyttal eller att man kan konvertera summan genom ((float)sum/ANTAL; så himla svårt o få grepp om allt alltså såhär i början.

Här är den nya koden, tror den uppfyller alla dina nya direktiv.
Finns det några andra tillfällen än vid just loopar det kan vara bra att deklarera/skapa en temporär variabel?
Finns det någon nackdel med att deklarera funktionerna högst upp så som jag gjort? Eller är det bättre att försöka lägga allting i ordning i programmet så man slipper deklarera?
Någon som vet hur man får å, ä och ö att fungera i code::blocks? (vid utskrifter dvs)

#include <stdio.h> #include <stdlib.h> #include <time.h> #define ANTAL 100 #define radStart 0 #define radEnd 10 #define kolumnStart 0 #define kolumnEnd 10 #define randMax 901 void printMenu(); void mrndgen(int lista[ANTAL]); void sort(int lista[ANTAL]); void med(int lista[ANTAL]); void graph(int lista[ANTAL]); void binarsok(int lista[ANTAL]); int main() { int failsafe = 0; int lista[ANTAL]; char choice = 0; while(choice != 5) { printMenu(); // här skriver vi ut menyn i en while-loop tills villkoret inte längre är uppfyllt. scanf(" %c", &choice); switch(choice) { case '1': mrndgen(lista); failsafe = 1; break; case '2': if(failsafe == 1){sort(lista); failsafe = 2;} else printf("Du måste ha en talfoljd."); break; case '3': if(failsafe == 2) med(lista); else printf("Du maste ha en sorterad talfoljd."); break; case '4': if(failsafe == 2) binarsok(lista); else printf("Du maste ha en sorterad talfoljd."); break; default: printf("Ogiltigt val."); } } return 0; } void printMenu() // skapar en meny { printf("\n/==========================================================================/\n"); printf("/=================================MENU=====================================/\n"); printf("/==========================================================================/\n"); printf("1. Alstra en talfoljd med en slumpgenerator och skriv ut talen pa skarmen.\n"); printf("2. Sortera talfoljden med bubbelsortering. Efter sorteringen skall talfoljden skrivas ut pa skarmen.\n"); printf("3. Medelvarde, median, maxvarde och minvarde skall beraknas och skrivas ut pa skarmen.\n"); printf("4. Med binarsokning skall man kunna soka efter ett valfritt tal. Om talet finns i talfoljden meddelas, pa skarmen,\n pa vilken plats i tabellen (rad och kolumn) talet finns. Annars meddelas att talet inte finns i talfoljden.\n"); printf("/==========================================================================/\n"); printf("/==========================================================================/\n"); printf("/==========================================================================/\n"); printf(">>: \n"); } void graph(int lista[ANTAL]) // skapar en 10*10 kolumn där int y är värdena vi ska lagra. { int x = 0; for(int rader = radStart; rader < radEnd; rader++) { for (int kolumner = kolumnStart; kolumner<kolumnEnd; kolumner++){ printf("%d \t", lista[x]); x++; // x börjar på 0 och går mot 100 då dessa tillsammans kommer köras 100 gånger. } printf("\n"); } } void mrndgen(int lista[ANTAL]) // skapar en slumpartad talföljd i en array. { srand(time(NULL)); int tal = 0; for(int i=0; i<ANTAL; i++) { tal = rand() % randMax; lista[i] = tal; } printf("***********************\n"); printf("*** Slumpad lista: ***\n"); printf("***********************\n"); graph(lista); } void sort(int lista[ANTAL]) // sorterar den slumpartade talföljden { int temp = 0; for(int i = 0; i < ANTAL-1; i++) { for(int j = 0; j < ANTAL-1-i; j++) { if(lista[j] > lista[j+1]) { temp = lista[j]; lista[j] = lista[j+1]; lista[j+1] = temp; } } } printf("***********************\n"); printf("*** Sorterad lista: ***\n"); printf("***********************\n"); graph(lista); } void med(int lista[ANTAL]) // Beräknar medelvärde, median,, min och max. { int max = 0, tal = 0, mini = 1000; float medel = 0, median = 0, median2 = 0, median1 = 0, sum = 0; for(int i=0; i<ANTAL; i++) { sum = sum + lista[i]; tal = lista[i]; if(tal < mini) mini = tal; if(tal > max) max = tal; } median2 = lista[ANTAL/2]; median1 = lista[ANTAL/2-1]; median = (median2+median1)/2; medel = sum/ANTAL; printf("*** The average is: %.2f, max is: %d min is: %d median is %.2f ***", medel, max, mini, median); } void binarsok(int lista[ANTAL]){ // Binärsökning. int v=0, h=ANTAL, mitten, sok; // v = startvärdet i arrayen upp till 100. Mitten blir alltså 100+0/2 = 50. Nästa mitt om > 50 = 100+50/2 = 75 osvosv. printf("\nAnge soktal: "); scanf("%d",&sok); while((h-v) > 1) { mitten=(v+h)/2; if(sok>=lista[mitten]) // ifall t.ex 20 >= mitten så är v (dvs 0) mitten. Och den letar då mellan 0-50 som steg 2. v=mitten; else h=mitten; // här blir 100 mitten så då letar den mellan 50-100 som steg 2. } if(sok==lista[v]) printf("Talet finns pa plats: %d\nRad: %d\nKolumn: %d\n",v+1, v/10+1, v%10+1); // Eftersom arrayen börjar på 0 och kolumnen på 1 så behöver man ta +1 för att få fram rätt. else printf("Talet finns inte i talfoljden\n"); }

Dold text
Visa signatur

10700K | NVIDIA RTX 3080

Permalänk
Medlem

@kwame: Som jag skrev tidigare i tråden så bör du inte anta att arrayerna har ANTAL element i dina funktioner, det är bättre att skicka med storleken som ett argument. Det är egentligen inte en array som skickas till funktionen, utan en pekare till arrayen. D.v.s. dessa deklarationer är ekvivalenta:

void sort(int lista[ANTAL]) void sort(int lista[]) void sort(int *lista)

I den första formen kommer kompilatorn alltså helt ignorera storleken på arrayen, så man kan se det som en kommentar om man vill. Det finns dock inget som hindrar någon från att skicka in en array med en annan storlek till funktionen.

Sen anser de flesta att man inte bör skriva if-satser utan måsvingar, t.ex.:

if (sok >= lista[mitten]) v=mitten; else h=mitten;

Problemet med detta är att det är lätt hänt att man då lägger till mer kod och glömmer bort att lägga till måsvingar, vilket resulterar i buggar:

if (sok >= lista[mitten]) v=mitten; else h=mitten; printf("something"); // Hoppsan, denna rad hör inte till if-satsen.

Om du tycker koden blir för "luftig" med måsvingar på egna rader så kan du använda samma stil som används i Linux-kärnan:

if (sok >= lista[mitten]) { v=mitten; } else { h=mitten; }

Det enda undantaget jag personligen gör är när man har en if-sats som kan skrivas på en rad:

if (x > 0) return;

Skrivet av kwame:

Finns det några andra tillfällen än vid just loopar det kan vara bra att deklarera/skapa en temporär variabel?

Över lag är det bäst att deklarera variabler så nära stället där de används som möjligt. Så i din med-funktion kan du t.ex. deklarera median-variablerna när du räknar ut medianen istället för i början av funktionen. D.v.s. försök deklarera variabler så att du direkt kan ge dem ett riktigt värde, istället för att deklarera dem i förtid och sätta dem till t.ex. 0. Att deklarera alla variabler i början av funktionen är en kvarleva från äldre versioner av C där detta var ett krav, men sen C99 kan man deklarera variabler lite vart man vill.

Skrivet av kwame:

Finns det någon nackdel med att deklarera funktionerna högst upp så som jag gjort? Eller är det bättre att försöka lägga allting i ordning i programmet så man slipper deklarera?

Det är mest en smaksak, det är inte alltid möjligt att lägga funktionerna i rätt ordning (t.ex. för att två funktioner anropar varandra). När man börjar skriva lite större program och delar upp koden i flera filer så deklarerar man de flesta av funktionerna i header-filer istället.

Permalänk
Medlem
Skrivet av perost:

Massa bra information!

Sådär, har ännu en gång ändrat koden! Känns som allt känns ganska glasklart så har egentligen inga direkta funderingar kring det du sa.
Om du inte har några sista synpunkter så kan jag bara säga tack så mycket för hjälpen. Känns som jag fått ett mycket bättre grepp om det hela nu.

#include <stdio.h> #include <stdlib.h> #include <time.h> #define ANTAL 100 #define radStart 0 #define radEnd 10 #define kolumnStart 0 #define kolumnEnd 10 #define randMax 901 void printMenu(); void mrndgen(int *lista); void sort(int *lista); void med(int *lista); void graph(int *lista); void binarsok(int *lista); int main() { int failsafe = 0; int lista[ANTAL]; char choice = 0; while(choice != 5) { printMenu(); // här skriver vi ut menyn i en while-loop tills villkoret inte längre är uppfyllt. scanf(" %c", &choice); switch(choice) { case '1': mrndgen(lista); failsafe = 1; break; case '2': if(failsafe == 1){sort(lista); failsafe = 2;} else printf("Du måste ha en talfoljd."); break; case '3': if(failsafe == 2) med(lista); else printf("Du maste ha en sorterad talfoljd."); break; case '4': if(failsafe == 2) binarsok(lista); else printf("Du maste ha en sorterad talfoljd."); break; default: printf("Ogiltigt val."); } } return 0; } void printMenu() // skapar en meny { printf("\n/==========================================================================/\n"); printf("/=================================MENU=====================================/\n"); printf("/==========================================================================/\n"); printf("1. Alstra en talfoljd med en slumpgenerator och skriv ut talen pa skarmen.\n"); printf("2. Sortera talfoljden med bubbelsortering. Efter sorteringen skall talfoljden skrivas ut pa skarmen.\n"); printf("3. Medelvarde, median, maxvarde och minvarde skall beraknas och skrivas ut pa skarmen.\n"); printf("4. Med binarsokning skall man kunna soka efter ett valfritt tal. Om talet finns i talfoljden meddelas, pa skarmen,\n pa vilken plats i tabellen (rad och kolumn) talet finns. Annars meddelas att talet inte finns i talfoljden.\n"); printf("/==========================================================================/\n"); printf("/==========================================================================/\n"); printf("/==========================================================================/\n"); printf(">>: \n"); } void graph(int *lista) // skapar en 10*10 kolumn där int y är värdena vi ska lagra. { int x = 0; for(int rader = radStart; rader < radEnd; rader++) { for (int kolumner = kolumnStart; kolumner<kolumnEnd; kolumner++){ printf("%d \t", lista[x]); x++; // x börjar på 0 och går mot 100 då dessa tillsammans kommer köras 100 gånger. } printf("\n"); } } void mrndgen(int *lista) // skapar en slumpartad talföljd i en array. { srand(time(NULL)); for(int i=0; i<ANTAL; i++) { int tal = rand() % randMax; lista[i] = tal; } printf("***********************\n"); printf("*** Slumpad lista: ***\n"); printf("***********************\n"); graph(lista); } void sort(int *lista) // sorterar den slumpartade talföljden { for(int i = 0; i < ANTAL-1; i++) { for(int j = 0; j < ANTAL-1-i; j++) { if(lista[j] > lista[j+1]) { int temp = lista[j]; lista[j] = lista[j+1]; lista[j+1] = temp; } } } printf("***********************\n"); printf("*** Sorterad lista: ***\n"); printf("***********************\n"); graph(lista); } void med(int *lista) // Beräknar medelvärde, median,, min och max. { int max = 0, mini = 1000; float sum = 0; for(int i=0; i<ANTAL; i++) { sum = sum + lista[i]; int tal = lista[i]; if(tal < mini) mini = tal; if(tal > max) max = tal; } float median2 = lista[ANTAL/2]; float median1 = lista[ANTAL/2-1]; float median = (median2+median1)/2; float medel = sum/ANTAL; printf("*** The average is: %.2f, max is: %d min is: %d median is %.2f ***", medel, max, mini, median); } void binarsok(int *lista){ // Binärsökning. int v=0, h=ANTAL, mitten, sok; // v = startvärdet i arrayen upp till 100. Mitten blir alltså 100+0/2 = 50. Nästa mitt om > 50 = 100+50/2 = 75 osvosv. printf("\nAnge soktal: "); scanf("%d",&sok); while((h-v) > 1) { mitten=(v+h)/2; if(sok>=lista[mitten]){// ifall t.ex 20 >= mitten så är v (dvs 0) mitten. Och den letar då mellan 0-50 som steg 2. v=mitten; }else{ h=mitten; // här blir 100 mitten så då letar den mellan 50-100 som steg 2. } }if(sok==lista[v]){ printf("Talet finns pa plats: %d\nRad: %d\nKolumn: %d\n",v+1, v/10+1, v%10+1); // Eftersom arrayen börjar på 0 och kolumnen på 1 så behöver man ta +1 för att få fram rätt. }else{ printf("Talet finns inte i talfoljden\n"); } }

Dold text
Visa signatur

10700K | NVIDIA RTX 3080

Permalänk

@kwame: En elak fråga: Vad händer med medianvärdet om ANTAL är udda?
Hur skulle det fungera om du använde ANTAL/2 och (ANTAL - 1)/2 som indexuttryck istället?

Permalänk
Skrivet av perost:

@kwame: Som jag skrev tidigare i tråden så bör du inte anta att arrayerna har ANTAL element i dina funktioner, det är bättre att skicka med storleken som ett argument. Det är egentligen inte en array som skickas till funktionen, utan en pekare till arrayen. D.v.s. dessa deklarationer är ekvivalenta:

void sort(int lista[ANTAL]) void sort(int lista[]) void sort(int *lista)

I den första formen kommer kompilatorn alltså helt ignorera storleken på arrayen, så man kan se det som en kommentar om man vill. Det finns dock inget som hindrar någon från att skicka in en array med en annan storlek till funktionen.

@kwame: Jag såg att du läst perosts kommentar ovan och bytt till int * överallt.

Detta är överkurs. Det funkar finfint med int * överallt, men att de tre exemplen ovan är likvärdiga ur kompilatorns synvinkel, är inte hela historien. Vilken du använder skickar en signal till den som läser koden. Själv föredrar jag void sort(int lista[]) när man skickar in en array (som kompilatorn omvandlar till en pekare till första elementet) och funktionen förväntas använda parametern som en array. Om argumentet jag skickar pekar på en skalär variabel (inte en array) och funktionen bara förväntas jobba med just den variabeln använder jag void func(int *p). Båda formerna är likvärdiga men de signalerar hur det är tänkt att parametern skall användas. Det här börjar närma sig filosofiska resonemang, men det är lite på samma plan som när dumsnuten påpekade att dina variabelnamn borde beskriva vad de innehåller eller hur de skall användas snarare än typen. Det må vara en array, men den kanske borde döpas efter vad den innehåller istället. På samma sätt, om parametern används som en array kanske int lista[] är bättre än int *lista.

Permalänk
Medlem
Skrivet av Ingetledigtnamn:

@kwame: En elak fråga: Vad händer med medianvärdet om ANTAL är udda?
Hur skulle det fungera om du använde ANTAL/2 och (ANTAL - 1)/2 som indexuttryck istället?

Haha, jag har faktiskt ställt mig själv den frågan hur jag ska lösa det eller om jag bara ska skita i det. Min spontana tanke först var att använda en if-sats att den bara skulle använda sig av median1 (eller 2) om det var udda typ...
Men verkar som lösningen är enklare än så i och med ditt svar. I mitt fall så får vi just nu ANTAL/2 = 50 och ANTAL/2-1 = 50-1 = 49
Och vid udda = 49.5 och 49.5-1 = 48.5. (dvs skulle detta inte fungera)

Med ditt så får man 50 och 49.5 vid jämnt och 49.5 och 49.5 vid udda. Hur tolkar kompilatorn att hämta [49.5] i en array? OM det nu fungerar på så vis att den läser det som 49 så skulle väl det bli fel i och med att mitten är 50 vid 99?

Skrivet av Ingetledigtnamn:

@kwame: Jag såg att du läst perosts kommentar ovan och bytt till int * överallt.

Detta är överkurs. Det funkar finfint med int * överallt, men att de tre exemplen ovan är likvärdiga ur kompilatorns synvinkel, är inte hela historien. Vilken du använder skickar en signal till den som läser koden. Själv föredrar jag void sort(int lista[]) när man skickar in en array (som kompilatorn omvandlar till en pekare till första elementet) och funktionen förväntas använda parametern som en array. Om argumentet jag skickar pekar på en skalär variabel (inte en array) och funktionen bara förväntas jobba med just den variabeln använder jag void func(int *p). Båda formerna är likvärdiga men de signalerar hur det är tänkt att parametern skall användas. Det här börjar närma sig filosofiska resonemang, men det är lite på samma plan som när dumsnuten påpekade att dina variabelnamn borde beskriva vad de innehåller eller hur de skall användas snarare än typen. Det må vara en array, men den kanske borde döpas efter vad den innehåller istället. På samma sätt, om parametern används som en array kanske int lista[] är bättre än int *lista.

Är sjuk och vet inte om jag har en otroligt seg hjärna för tillfället men förstår inte riktigt ditt svar?
Förstår inte riktigt för- och nackdel med *lista vs lista[] om nu båda (i just detta scenariot fungerar)?

Det jag fått höra på lektioner om pekare är att om man ändrar något i den senare så ändrar den det även i det ursprungliga, och det kan ju vara både en för- och nackdel beroende på vad man vill göra.

Eller jaha, du menar generellt sett så bör man använda [] när det handlar om arrayer och *p (pekare) när det faktiskt handlar om enskilda variabler?

Visa signatur

10700K | NVIDIA RTX 3080

Permalänk
Medlem
Skrivet av kwame:

Eller jaha, du menar generellt sett så bör man använda [] när det handlar om arrayer och *p (pekare) när det faktiskt handlar om enskilda variabler?

För kompilatorn är det som sagt ingen skillnad, utan skillnaden är vad koden säger till de som läser den. Om en funktion har en parameter som är deklarerad som [] så kommunicerar det att funktionen förväntar sig en array, även om kompilatorn egentligen inte bryr sig om man skickar in en array eller en pekare. C har ett väldigt tillåtande typsystem, så man får ta all hjälp man kan få för att försöka undvika att funktioner anropas med fel argument.

Och lite rolig överkurs gällande arrayer och pekare: när man subskriptar en array, t.ex. x[0] för att få ut det första elementet, så översätts det till *(x + 0) av kompilatorn. Och eftersom x + 0 är samma sak som 0 + x så kan man vända på det och skriva 0[x] istället. Bra sätt att göra andra utvecklare förbannade på en

Permalänk
Skrivet av kwame:

Haha, jag har faktiskt ställt mig själv den frågan hur jag ska lösa det eller om jag bara ska skita i det. Min spontana tanke först var att använda en if-sats att den bara skulle använda sig av median1 (eller 2) om det var udda typ...
Men verkar som lösningen är enklare än så i och med ditt svar. I mitt fall så får vi just nu ANTAL/2 = 50 och ANTAL/2-1 = 50-1 = 49
Och vid udda = 49.5 och 49.5-1 = 48.5. (dvs skulle detta inte fungera)

Med ditt så får man 50 och 49.5 vid jämnt och 49.5 och 49.5 vid udda. Hur tolkar kompilatorn att hämta [49.5] i en array? OM det nu fungerar på så vis att den läser det som 49 så skulle väl det bli fel i och med att mitten är 50 vid 99?

Nu måste vi komma ihåg det här med heltal och flyttal. Så länge båda operanderna är heltal kommer division göras som heltalsdivision, alltså decimalerna trunkeras. Med ANTAL = 100 får du då 100 / 2 = 50 och 99 / 2 = 49. Med ANTAL = 101 får du 101 / 2 = 50 och 100 / 2 = 50 och din medianberäkning kommer då ta (lista[50] + lista[50]) / 2.0. Din beräkning kommer bli korrekt oavsett om ANTAL är udda eller jämn.

Skrivet av kwame:

Eller jaha, du menar generellt sett så bör man använda [] när det handlar om arrayer och *p (pekare) när det faktiskt handlar om enskilda variabler?

Precis. Det spelar ingen roll för koden som kompilatorn genererar, men det kan göra det lättare att förstå koden.

Permalänk
Medlem

Hej igen!
Någon som kodar i Windows-miljö?
Vad ska man använda?

Märkte idag när uppgiften skulle in att code::blocks tydligen inte är så optimalt trots allt. (Har nu efter detta missödet installerat Ubuntu och kör dual-boot på min laptop där jag kör sublimetext) men har ingen lust med dualboot på min stationära så tänkte om det finns något relativt pålitligt program jag kan köra när jag kodar? (Kommer testköra det på laptopen innan jag lämnar in programmet iaf.

Här är dagens problem iaf, denna biten kod fungerade perfekt i codeblocks. Sedan när jag körde det i min kompis dator som kör i Ubuntu (och en annan som kör på Mac) så fick jag hela tiden: "Du måste ha en talfoljd." efter man tryckt på 1an. Jag testade att ändra min failsafe till 2,3,4 och satte den till int failsafe = 1; till att börja med. Ändå så skrev den ut "Du måste ha en talfoljd." (0) dvs den ändrade failsafe till 0, trots att den var 1 från början.

Sorgligt nog tog det en hel timme att fatta att av någon anledning så var problemet att den läste in det som en string och lagrade i character utan att det var en array och det blev någon typ av overflow som sabbade hela koden. (Men ja, varför fungerade det ens i codeblocks?)

int failsafe = 0; int lista[ANTAL]; char choice = 0; while(choice != 5) { printMenu(); // här skriver vi ut menyn i en while-loop tills villkoret inte längre är uppfyllt. scanf(" %s", &choice); switch(choice) { case '1': mrndgen(lista); failsafe = 1; break; case '2': if(failsafe == 1){sort(lista); failsafe = 2;} else printf("Du måste ha en talfoljd."); break; case '3': if(failsafe == 2) med(lista); else printf("Du maste ha en sorterad talfoljd."); break; case '4': if(failsafe == 2) binarsok(lista); else printf("Du maste ha en sorterad talfoljd."); break; default: printf("Ogiltigt val."); }

Dold text
Visa signatur

10700K | NVIDIA RTX 3080

Permalänk

I din "gamla" kod står det %c i scanf-anropet, här står det %s. %c läser in ett tecken (char) och %s läser en sträng (en sekvens av char). Att försöka läsa in en sträng i choice lär ha skrivit över slumpvisa saker på stacken Här ser du precis hur typsäkert C är.

Permalänk
Medlem

Hallå där!
Har en ny liten fundering.
Har gjort en relativt (för mig) stor uppgift i att skapa ett fordonsregister där man sparar diverse fordonsuppgifter samt användaruppgifter i en struct och sedan skriver dessa till en fil.
Sedan när programmet startas så läses all information in från en fil och man ska direkt kunna arbeta med uppgifterna igen.

Min fråga:
Just nu har jag en key kopplad till varje fordon som berättar om en plats är tagen (1) eller tom (0) och när programmet startas så går den for(i=0; i<antalfordon; i++) och kollar vilka platser som är upptagna eller inte.

Hur kan jag göra för att skippa att ha en key? Eller är detta ett bra sätt? Tänkte om man har en miljard fordon så känns det ju ganska tungt att den ska behöva gå igenom alla dom och räkna manuellt.

Fråga nummer två: Hur skriver man egentligen en struct till en fil och med dynamiskt allokerat minne?

Just nu har jag en struct som heter fordon car och en som heter user, user ligger innuti fordon.
Jag skriver den på så vis att jag kör fwrite(car,sizeof(vehicle),*counter,file)) -> counter är en pekare med mängden fordon i registret.
och fread på samma vis. Detta fungerar MEN jag ser att i de flesta exemplen så har de ett fwrite(&car... vad är skillnaden? Kör jag med det exemplet så får jag segmentation overflow (eller vad de nu stod)

Här är koden för den som vill kika närmare:
https://workupload.com/start/fVvFXGsQ

Eller om ni inte orkar ladda ner: (Filhantering ser ni iallafall mina read- och writefunktioner.)

main:

#include "definitions.h" /*char inputSingleChar(int length) { char safeInput[100] = {'0'}; scanf("%s", safeInput[0]); while(strlen(safeInput)>length) { printf("Too long input."); scanf("%s", safeInput[0]); if(strlen(safeInput==1)) return safeInput[0]; } return safeInput[0]; }*/ void qCarType(vehicle car[], int i) // Gör en valbar meny för typer av fordon. { char input; printf("Which car type do you have?\n"); printf("1: Petrol\n"); printf("2: Diesel\n"); printf("3: Hybrid\n"); printf("4: Electric\n"); scanf(" %c", &input); switch(input) { case '1': strcpy(car[i].type, "Petrol"); break; case '2': strcpy(car[i].type, "Diesel"); break; case '3': strcpy(car[i].type, "Hybrid"); break; case '4': strcpy(car[i].type, "Electric"); break; default: printf("Please input a number between 1-4"); } } int countCars(vehicle car[]) // Räknar antalet fordon när vi startar programmet. { int key = car[0].key, i = 0; while(key == 1 && i < REGISTER_SIZE) { key = car[i].key; if(key != 1){return i;} i++; // printf("Key: %d i: %d\n", key, i); --> DEBUG if(i >= REGISTER_SIZE){printf("Register is full!\n"); return i; } } } int addVehicle(vehicle car[], int *count) // Lägger till Fordon. { int i = 0; if(*count >= REGISTER_SIZE){printf("Register is full!\n"); return 0; } i = *count; printf("What is the car brand?\n>>:"); //Frågar efter värden för "vehicle" scanf("%s", car[i].brand); printf("What is the car type?\n>>"); qCarType(car, i); printf("Selection: %s\n", car[i].type); printf("What is the registration number?\n>>"); scanf("%s", car[i].reg); printf("What is your Firstname?\n>>:"); //Frågar efter värden för "user" scanf("%s", car[i].user.firstName); printf("What is your Surname?\n>>:"); scanf("%s", car[i].user.lastName); printf("How old are you?\n>>:"); scanf("%d", &car[i].user.Age); car[i].key = 1; *count = *count + 1; printf("Car successfully added to registry.\n"); return 0; } int deleteVehicle(vehicle car[], int *count) // Tar bort fordon. { int input; printf("Which user do you want to remove?: \n"); scanf("%d", &input); input--; if(input > *count){printf("This vechicle does not exist.\n"); return 0;} // car[input-1].key = 0; for(input; input<*count; input++) { memcpy(&car[input], &car[input+1], sizeof(vehicle)); } printf("Car #%d successfully deleted.", *count); *count = *count - 1; // printf("COUNTER == %d\n", *count); --> DEBUG return 0; } int sortVehicle(vehicle car[], int *count) // Sorterar fordon efter märke. { vehicle temp[REGISTER_SIZE]; if (*count < 2) { printf("To few vehicles in the registry, you must have atleast 2.\n"); return 0; } for(int i=0; i<*count-1; i++) { for(int j=0; j<*count-i; j++) { if((strcmp(car[j].brand,car[j+1].brand) >0) && (car[j+1].key == 1)) { memcpy(&temp, &car[j], sizeof(vehicle)); memcpy(&car[j], &car[j+1], sizeof(vehicle)); memcpy(&car[j+1], &temp, sizeof(vehicle)); } } } return 0; } int printVehicle(vehicle car[], int *count) // Skriver ut fordonet som användaren väljer. { // printf("COUNTER == %d\n", *count); --> DEBUG int i; printf("Which vehicle do you want to see? \n>>:"); scanf("%d", &i); if(i > *count){printf("This car does not exist. Try with another.\n"); return 0;} printf("vehicle number %d: \n", i); printf("A %s %s with reg: %s\n", car[i-1].brand, car[i-1].type, car[i-1].reg); printf("The owner is: %s %s, %d years old.\n", car[i-1].user.firstName, car[i-1].user.lastName, car[i-1].user.Age); return 0; } int printAllVehicle(vehicle car[], int *count) // Skriver ut alla fordon i registret. { int i = 0; // printf("COUNTER == %d\n", *count); --> DEBUG if(*count == 0){printf("No cars in registry. Please add with menu option 1 first.\n"); return 0;} printf("user details: \n"); for(i=0;i<REGISTER_SIZE;i++) { if(car[i].key == 1) { printf("vehicle number %d: \n", i+1); printf("--> A %s %s with reg: %s\n", car[i].brand, car[i].type, car[i].reg); printf("--> The owner is: %s %s, %d years old.\n", car[i].user.firstName, car[i].user.lastName, car[i].user.Age); } } return 0; } void printMenu() // Skriver ut menyn. { printf("\n1.Add vehicle:\n"); printf("2.Remove vehicle:\n"); printf("3.Sort vehicle by brand:\n"); printf("4.Print vehicle information:\n"); printf("5.Print entire vehicle registry:\n"); printf("6.Save and Quit. \n"); printf(">>: \n"); } int main() // Huvudprogram. { vehicle car[REGISTER_SIZE]; int counter = 0; //DEKLARERING AV COUNTER readFile(car); // Här kallar vi på Readfile där vi läser in structen. counter = countCars(car); // Här räknar vi antalet fordon som fanns i structen. char choice[100] = {'0'}; int i = 0; printf("** MENU ** \n"); while(i == 0) { printMenu(); scanf(" %s", &choice[0]); switch(choice[0]) { case '1': addVehicle(car, &counter); break; case '2': deleteVehicle(car, &counter); break; case '3': sortVehicle(car, &counter); break; case '4': printVehicle(car, &counter); break; case '5': printAllVehicle(car, &counter); break; case '6': writeFile(car, &counter); break; default: printf("Faulty input, please try again!"); } } return 0; }

Dold text

Definitioner:

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define REGISTER_SIZE 10 #define USER_NAME_LEN 50 typedef struct { char firstName[USER_NAME_LEN]; char lastName[USER_NAME_LEN]; int Age; }owner; typedef struct { owner user; char brand[USER_NAME_LEN]; char type[USER_NAME_LEN]; int key; char reg[6]; }vehicle; int readFile(); int writeFile(); int countCars(vehicle car[]);

Dold text

filhantering:

#include "definitions.h" int readFile(vehicle car[]) { FILE *file; file = fopen("records.txt", "r"); // öppnar en read-only version av records.txt if (!file) // ifall filen inte kan öppnas { printf("File could not be opened\n**Creating New File**\a\a"); file = fopen("records.txt", "w+"); for (int i = 0; i < REGISTER_SIZE; i++) { car[i].key = 0; } fwrite(car, sizeof(vehicle), REGISTER_SIZE, file); } fread(car, sizeof(vehicle), REGISTER_SIZE, file); fclose(file); return 0; } int writeFile(vehicle car[], int *count) { FILE *file; file = fopen("records.txt", "w+"); // "a" innebär att man ska påbörja där man sist avslutade i textfilen. if (!file) // ifall filen inte kan öppnas { printf("File could not be opened\n\a\a"); return -1; } fwrite(car, sizeof(vehicle), *count, file); // ny testkod printf("\nData is stored succesfully!\n"); // ny testkod fclose(file); exit(0); }

Dold text
Visa signatur

10700K | NVIDIA RTX 3080

Permalänk
Medlem
Skrivet av kwame:

Just nu har jag en key kopplad till varje fordon som berättar om en plats är tagen (1) eller tom (0) och när programmet startas så går den for(i=0; i<antalfordon; i++) och kollar vilka platser som är upptagna eller inte.

Hur kan jag göra för att skippa att ha en key? Eller är detta ett bra sätt? Tänkte om man har en miljard fordon så känns det ju ganska tungt att den ska behöva gå igenom alla dom och räkna manuellt.

I just det här fallet är det väl en rimlig lösning, eftersom du allokerar allt minne statiskt på stacken. D.v.s. allt minne allokeras när programmet startar, så alla fordon existerar även om de inte blivit tilldelade några värden än. Skulle du öka REGISTER_SIZE till säg 100,000 eller mer så skulle programmet krascha eftersom stackminnet är ganska begränsat (några MB).

I ett "riktigt" program skulle man allokera minne dynamiskt istället, d.v.s. med malloc. Om man inte vet hur många element man behöver lagra så är en vanlig taktik att allokera en lagomt stor array, och tar den slut så allokerar man en ny array som t.ex. är dubbelt så stor och kopierar över den gamla arrayen till den nya. Det är så t.ex. std::vector i C++ fungerar, men i C får man förstås sköta sånt mer manuellt.

Istället för en array så finns det även många andra datastrukturer som kanske skulle vara lämpligare om man har många fordon, t.ex. en hashtabell med fordonets registreringsnummer som nyckel.

Skrivet av kwame:

Fråga nummer två: Hur skriver man egentligen en struct till en fil och med dynamiskt allokerat minne?

Du har inget dynamiskt allokerat minne i ditt program, bara så att du är medveten om det. Men om du skulle ha det så kan du inte längre bara skriva ut hela strukturen rakt av, eftersom den skulle innehålla pekare till det allokerade minnet. Då får du helt enkelt implementera särskilda funktioner som dumpar och läser in strukturerna, antingen genom att använda ett format du själv hittar på eller genom att använda ett existerande format som t.ex. JSON.

Det handlar bara om att skriva ut datan på ett sätt som gör att du kan läsa in den igen. För strängar kan man t.ex. skriva ut storleken på strängen först, så att man vet hur lång strängen är. Ett annat alternativ är att skriva ut en speciell karaktär i slutet av strängen och sen läsa in karaktärer tills man når den.

Skrivet av kwame:

Just nu har jag en struct som heter fordon car och en som heter user, user ligger innuti fordon.
Jag skriver den på så vis att jag kör fwrite(car,sizeof(vehicle),*counter,file)) -> counter är en pekare med mängden fordon i registret.
och fread på samma vis. Detta fungerar MEN jag ser att i de flesta exemplen så har de ett fwrite(&car... vad är skillnaden? Kör jag med det exemplet så får jag segmentation overflow (eller vad de nu stod)

Det borde fungera att skriva &car, det kan hända att du har något annat fel någonstans. Att det går att skriva bara car är p.g.a. att car är en array, så den fungerar som en pekare när den används som ett funktionsargument. Skillnaden är att &car ger en pekare till hela arrayen, medan car pekar på det första elementet. D.v.s. car + 1 pekar på det andra elementet, medan &car + 1 pekar på adressen efter arrayen. Men det ska inte spela någon roll här.

Permalänk
Medlem

Sitter nu och försöker lära mig pekare till tentan - men jag lyckas verkligen inte lösa en tidigare tenta-uppgifter gällande pekare. Har kollat YouTube videos men blir inte riktigt nå smartare, tycker de går igenom så få exempel, kanske bara jag som är trög men.

Här är uppgiften iaf: "Rita bilder och förklara vvad som händer i nedanstående uppgift. Om någon minnescell innehåller obestämda värden (skräp) kan du rita ett '?' på lämpligt ställe i bilden. Har skrivit mitt försök i koden. Säkerligen många fel..

char x = 'u', *p1, *p2; ---> skapar pekare *p1 och *p2, ger variabeln x värdet 'u'. p1 = &x; -> p1 pekar på adressen till x. p2 = (char*)malloc(2*sizeof(char)); -> p2 allokerar minne med storleken av 2 char. p2[0] = ? och p2[1] = ? *(p2) = 'k'; -> (Pekar p2 på 'k' här eller får första minnescellen 'k' här?) *p1 = *p1+2; -> p1 pekar på u som blir u+2 -> W. (detta är fortfarande vad x är) p1 = p2+1; -> p1 pekar nu på p2+1 som är k+1 = L *p2-=2; (Har ingen aning vad detta innebär) *p1=*p2+5; (denna är svår i och med att jag inte vet vad den föregående är) printf("%c%c%c!\n", x,*p2,*p1);

Hur skiljer det sig egentligen när det står typ
p1 = p2+1
jmf med *p1 = *p2+1 ?

Tycker allt är väldigt rörigt.

Visa signatur

10700K | NVIDIA RTX 3080

Permalänk
Medlem

@kwame: *p betyder att man refererar till det som p pekar på. Så t.ex. *p2 = 'k' betyder inte att p2 pekar på 'k', utan att man lagrar värdet 'k' i minnet som p2 pekar på. När man däremot säger p2 + 1 så är det själva addressen som p2 pekar på som man lägger till 1 på.

*p2 -= 2 är för övrigt ett kortare sätt att skriva *p2 = *p2 - 2 om du inte stött på den syntaxen tidigare.

Permalänk
Medlem
Skrivet av perost:

@kwame: *p betyder att man refererar till det som p pekar på. Så t.ex. *p2 = 'k' betyder inte att p2 pekar på 'k', utan att man lagrar värdet 'k' i minnet som p2 pekar på. När man däremot säger p2 + 1 så är det själva addressen som p2 pekar på som man lägger till 1 på.

*p2 -= 2 är för övrigt ett kortare sätt att skriva *p2 = *p2 - 2 om du inte stött på den syntaxen tidigare.

Ah, lysande! Nu fattar jag. Tack!

Visa signatur

10700K | NVIDIA RTX 3080

Permalänk
Medlem

edit: Tydligen jag som missförstått lotto. Tydligen måste inte alla vara i ordning.

Hmm, fick en idé att testa lite sannolikhetslära.
Chansen att vinna på lotto ska vara 1 på ca 6.7 miljoner.
Så jag gjorde då ett program som slumpar 7 unika siffror och jämför detta mot jackpoten (1,2,3,4,5,6,7)

Jämför jag mot alla 7 siffror så verkar den aldrig ta slut.
Men även när jag bara köra 5 siffror så får jag EXTREMT många kombinationer. Mina 2 senaste försök var 63 och 168 MILJONER...? Vart går de galet? Ps. har kommenterat bort jämförelsen på [5] och [6] i koden nedanför.

#include <stdio.h> #include <time.h> #include <stdlib.h> int main() { srand(time(NULL)); int lotto[8] = {1,2,3,4,5,6,7}; int lotto2[8]; int True = 0; long double antal = 0; while(True == 0) { for(int i=0; i<7; i++) { lotto2[i] = rand() % 35+1; for(int j=0; j<i; j++) { if(lotto2[i] == lotto2[j]) { i--; } } } antal++; if(lotto[0] == lotto2[0] && lotto[1] == lotto2[1] && lotto[2] == lotto2[2] && lotto[3] == lotto2[3] && lotto[4] == lotto2[4])// && lotto[5] == lotto2[5] && lotto[6] == lotto2[6]) True = 1; } antal = antal/1000000; printf("Number of tries: %.0Lf million", antal); }

Visa signatur

10700K | NVIDIA RTX 3080