Göra en meny och case funktion.
Hej, jag har fastnat på en uppgift där jag ska skriva ett program som genererar en slumpmässig talföljd med 100 olika positiva tal där programmet ska ha fem olika funktioner i en meny, talföljden ska ha 10 kolumner och 10 rader. De olika funktionerna är 1. Generera en talföljd 100 tal mellan 0</ x </900. 2 sortera den med bubble sort. 3, beräkna max,min medelvärde och median. 4. låta en person skriva in ett tal och genom binärsökning ska talets plats, rad och kolumn skrivas ut. och sista är 0 som avslutar program. val 2 3 4 kan inte göras om 1 inte har gjorts och 3 och 4 kan inte göras om 2 inte har gjorts, ogiltigt val ska skrivas ut som felmeddelande och menyn ska visas upp igen.
Detta är vad jag har kommit fram till hittills:
Min fråga är nu hur jag ska införa flaggor för att avgöra om valet är giltigt och hur programmet ska fortsätta om man väljer ett korrekt val och om det är inte rätt hur man kommer tillbaka till menyn igen?
Allt funktioner ska skrivas i egna funktioner utanför main vilket jag inte har kommit till än och inte riktigt vet hur jag ska göra.
Några kommentarer
scanf("%d", &val);
ger dig ett heltal, inte ASCII värdet av siffran ('1'). Om du vill ha ASCII värdet, använd " %c"
men talet är egentligen vad du vill ha, det blir lättare att hantera. Lägg också alltid till ett mellanslag framför format specificeringen ifall du har flera scanf som kör efter vartannat så att ENTER ignoreras (dvs " %d") i bufferten.
När man har all kod i main() blir programmet oläsligt, minst varje meny funktion borde vara i en egen funktion. En funktion som visar menyn och som returnerar valet hade varit fint också.
I din switch statement har du inga "break;" mellan de olika case satserna, vad som händer då är det "faller igenom" dvs efter '1' kommer case '2' att köras osv. Om det är så du vill ha det, är det bra att skriva en kommentar om det, annars skriv break;
Tänk på att när du delar heltal med andra heltal får heltal som resultat det kanske inte är vad du är ute efter. Dvs 12/15 blir 0.
För att återkomma till din fråga, så tror jag din fråga löses av sig själv om du splittar upp programmet i funktioner, en meny
funktion kunde hantera felaktig inmatning. Lägg sen en loop runt det tills rätt meny punkt väljs.
Exempel
int val = 0;
do
{
val = meny();
switch (val)
{
case 0:
break;
case 1:
GenSlumpTal(tal);
break;
case 2:
Sortera(tal);
break;
osv.
default:
printOgiltligt();
break;
}
}
while (val != 0);
Använd aldrig scanf. Läs in en rad i taget och använd sscanf.
Jag fattar inte heller varför de envisas med att använda scanf på våra lärosäten, det vore bättre de lärde ut rätt från början
fgets + sscanf
Vad är det för skillnad mellan sscanf och scanf? och hur implemeterar jag det?
char buffer[256];
if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
if (sscanf(buffer, "%d", &val) == 1) {
printf("ditt val var %d\n", val);
}
else {
puts("ogiltligt");
}
}
Okej men hur ska jag göra med egna funktioner vad varje funktion? {
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#define SIZE 100
int slumptal()
int main() {
int tal[SIZE] = {0};
int i = 0;
srand(time(NULL));
for(i = 0; i < SIZE; i++) {
tal[i] = rand() % 901;
}
for(i = 0; i < SIZE; i++) {
printf("%4d", tal[i]);
if(i % 10 == 9)
printf("\n");
}
return 0;
}
}
Jag fattar inte riktigt vad som ska in i int slumptal() och vad som ska stanna kvar
t.ex.
void GenereraSlumptal(int* tal, size_t storlek)
{
for (size_t i = 0; i < storlek;++i)
{
tal[i] = rand() % 901;
}
}
void SkrivUt(int* tal, size_t storlek)
{
...
}
Hur ser detta ut?
första bilden är i main()
Du får skicka in arrayen som parameter annars är funktionerna ganska verkningslösa
typ som jag visade i förra meddelandet.
Du deklarerar den i main() och skickar in den i funktionerna.
Du skriver fortfarande scanf("%d",&val) och sen kollar ASCII värdet - det kommer inte att fungera.
Gör en funktion som läser tangenbordet och returnerar vad användaren valt i området [0,4]
Se föregående post hur man bäst läser från tangentbordet med fgets/sscanf
sedan i din switch kollar du mot värdena case 1: , case 2: osv.
Bäst om du låter dina funktioner ta två parametrar, pekaren och storleken
void sortering(int* tal, size_t size)
{
int i = 0;
int j = 0;
...
if (tal[j]...
}
blir detta rätt?
Det blir fel fortfarande fel
< printf()>
Felmeddelande som du visade har sscanf(val, "%c", &val)
- det är förstås fel .
// gör en liten funktion som läser nummret.
int getNumber()
{
int number = -1;
if (fgets(buffer,sizeof(buffer),stdin)!=NULL)
{
if (sscanf(buffer, "%d", &number) == 1)
{
return number;
}
}
return -1;
}
// sen när du läser in efter du har visat menyn :
switch (getNumber()) {
case 1:
...
break;
...
case -1:
puts("ogiltligt värde");
break;
}
Okej nu ser det ut såhär men när jag kör programmet blir det totalt galet. Menyn bara visas upp om igen och jag kan inte välja värde. Hur kan jag lösa detta?
buffer är lite liten. Det kanske är därför.
Du hade nåt som hette SIZE förut.
SIZE var för for-loopen som jag definierade till 100 för att få 100 slumptal. Testade att byta 0 mot SIZE i bufferten med det blev samma sak med programmet
Jag ser inte vad som är fel. Stoppa in printf här och där i getnumber så vi ser vad som händer.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define SIZE 100
#define N 10
#define INVALID 0
#define VALID 1
void slumptal() {
//slumptal generator
int tal[SIZE] = {0};
int i = 0;
srand(time(NULL));
for(i = 0; i < SIZE; i++) {
tal[i] = rand() % 901;
}
for(i = 0; i < SIZE; i++) {
printf("%4d", tal[i]);
if(i % 10 == 9)
printf("\n");
}
}
void sortering() {
//sortering av genererade tal
int tal[SIZE] = {0};
int i = 0;
int j = 0;
int temp = 0;
for (int i = 0 ; i < SIZE; i++)
{
for (int j = 0; j < SIZE - 1; j++)
{
if (tal[j] > tal[j+1])
{
temp = tal[j];
tal[j] = tal[j+1];
tal[j+1] = temp;
}
}
}
for(i = 0; i < SIZE; i++) {
printf("%4d", tal[i]);
if(i % 10 == 9)
printf("\n");
}
}
void calculations() {
//max och min
int tal[SIZE] = {0};
int i = 0;
int max = 0;
int min = 900;
int summa = 0;
double medel = 0;
double median = 0;
for(i = 0; i < SIZE; i++){
if(tal[i] > max) {
max = tal[i];
}
if(tal[i] < min) {
min = tal[i];
}
}
//medelvärde
for(i = 0; i < SIZE; i++) {
summa += tal[i];
}
medel = summa / SIZE;
//median
median = (tal[49] + tal[50])/2;
printf("Max: %d Min: %d Medelvärde: %f Median: %f\n", max, min, medel, median);
}
void binsearch() {
//binärsökning
int tal[SIZE] = {0};
int i = 0;
int pos = 0; //position
int start = 0; //starposition i vektor
int slut = 99; //slutposition i vektor
int nummer = 0;
int flag;
int rad = 0; //rad
int kol = 0; //kolumn
printf("Skriv in ett nummer: \n");
scanf("%d", &nummer);
flag = 0;
while(start <= slut) {
pos = (start + slut)/2;
if(tal[pos] == nummer){
rad = (pos / N) + 1;
kol = (pos % N) + 1;
printf("Talet %d hittades på position %d samt på rad %d och kolumn %d\n", nummer, pos, rad, kol);
flag = 1;
break;
}
else if(tal[pos] < nummer)
start = pos + 1;
else if(tal[pos] > nummer)
slut = pos - 1;
break;
}
if(flag == 0)
printf("Talet finns ej\n");
}
void printmeny() {
//meny
printf("Meny\n");
printf("1. Generera en slumpgenerator\n");
printf("2. Sortera de genererade talen\n");
printf("3. Beräkna medelvärde, median samt max och min värde\n");
printf("4. Sök efter tal\n");
printf("0. Avsluta programmet\n");
}
int getNumber() {
char buffer[] = {100};
int number = -1;
if (fgets(buffer,sizeof(buffer),stdin)!=NULL)
{
if (sscanf(buffer, "%d", &number) == 1)
{
return number;
}
}
return -1;
}
int main() {
srand(time(NULL));
int nummer = 0;
int flag;
int rad = 0; //rad
int kol = 0; //kolumn
do {
printmeny();
switch(getNumber(printf("%d", number))) {
case 1 :
slumptal();
break;
case 2 :
sortering();
break;
case 3 :
calculations();
break;
case 4 :
binsearch();
break;
case 0 :
break;
case -1 :
printf("Ogiltigt val");
break;
}
} while(getNumber() != 0);
return 0;
}//nu står det error number undeclared när jag kör programmet
Nu står det error number undeclared när jag kör programmet, vart ska jag lägga in printf?
I funktionen, inte i anropet.
Såhär? Blir samma resultat
Jag har ändrat lite nu och det har blivit bättre men allt funkar inte riktigt. Det går inte att skriva in vilket case jag vill ha utan visar bara upp menyn. Alla funktioner funkar utom binärsökningen som skriver ut att talet inte finns fast det finns i sekvensen?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define SIZE 100
#define N 10
void slumpTal( int tal[SIZE], size_t size )
{
int i= 0;
srand(time(NULL));
for(i = 0; i < SIZE; ++i)
{
tal[i] = rand() % 901;
}
for(i = 0; i < SIZE; i++) {
printf("%4d", tal[i]);
if(i % 10 == 9)
printf("\n");
}
}
void sort( int tal[SIZE], size_t size )
{
int i = 0;
int j = 0;
for (i = 0 ; i < SIZE; i++)
{
for (j = 0; j < SIZE - 1; j++)
{
if (tal[j] > tal[j+1])
{
int temp = tal[j];
tal[j] = tal[j+1];
tal[j+1] = temp;
}
}
}
for(i = 0; i < SIZE; i++) {
printf("%4d", tal[i]);
if(i % 10 == 9)
printf("\n");
}
}
void calculations(int tal[SIZE], size_t size) {
//max och min
int i = 0;
int max = 0;
int min = 900;
int summa = 0;
double medel = 0;
double median = 0;
for(i = 0; i < SIZE; i++){
if(tal[i] > max) {
max = tal[i];
}
if(tal[i] < min) {
min = tal[i];
}
}
//medelvärde
for(i = 0; i < SIZE; i++) {
summa += tal[i];
}
medel = summa / SIZE;
//median
median = (tal[49] + tal[50])/2;
printf("Max: %d Min: %d Medelvärde: %f Median: %f\n", max, min, medel, median);
}
void binsearch(int tal[SIZE], size_t size) {
//binärsökning
int i = 0;
int pos = 0; //position
int start = 0; //starposition i vektor
int slut = 99; //slutposition i vektor
int nummer = 0;
int flag;
int rad = 0; //rad
int kol = 0; //kolumn
printf("Skriv in ett nummer: \n");
scanf("%d", &nummer);
flag = 0;
while(start <= slut) {
pos = (start + slut)/2;
if(tal[pos] == nummer){
rad = (pos / N) + 1;
kol = (pos % N) + 1;
printf("Talet %d hittades på position %d samt på rad %d och kolumn %d\n", nummer, pos, rad, kol);
flag = 1;
break;
}
else if(tal[pos] < nummer)
start = pos + 1;
else if(tal[pos] > nummer)
slut = pos - 1;
break;
}
if(flag == 0)
printf("Talet finns ej\n");
}
void printMeny() {
//meny
printf("Meny\n");
printf("1. Generera en slumpgenerator\n");
printf("2. Sortera de genererade talen\n");
printf("3. Beräkna medelvärde, median samt max och min värde\n");
printf("4. Sök efter tal\n");
printf("0. Avsluta programmet\n");
}
int getNumber()
{
char buffer[] = {100};
int number = -1;
if (fgets(buffer,sizeof(buffer),stdin)!=NULL)
{
if (sscanf(buffer, "%d", &number) == 1)
{
return number;
}
}
return -1;
}
int main()
{
int data[SIZE];
int val;
do
{
printMeny();
switch(getNumber()) {
case 0 :
break;
case 1 :
slumpTal( data, SIZE );
break;
case 2 :
sort( data, SIZE );
break;
case 3 :
calculations( data, SIZE);
break;
case 4 :
binsearch(data, SIZE);
break;
case -1 :
printf("Ogiltigt val\n");
break;
}
} while(val != 0);
return 0;
}
Varför skriver du så här?
char buffer[] = {100};
Du får då en buffer som är 1 byte stor med ASCII värdet 100
Skriv istället
char buffer[100] = {0};
Du behöver inte snåla med utrymmet :)
Du använder fortfarande scanf i dina andra funktioner
Om du sedan tidigare ropat scanf("%d") och lyckats få ut ett nummer så kommer \n att förbli i inbufferten, sedan kommer alla efterföljande anrop till scanf("%d",&v) att fallera, eftersom scanf letar efter ett heltal i inbufferten men hittar en \n.
Det är därför man har ett mellanslag framför %d så att det står scanf(" %d",&v); då ignoreras ev. \n framför nummret.
Gör det enkelt för dig istället och gör all inläsning från tangentbordet med fgets/sscanf.
Ser det här rätt ut? Blir samma resultat med binärsökningen att det står att talet inte finns, när det finns i sekvensen.
Om det ser ut så här från början
pos
|---------|---------|
start slut [start,slut]
Och om ditt nummer är mindre än tal[pos] då borde det nya intervallet du skall kolla i vara [start, pos - 1]
Om ditt nummer är större än tal[pos], borde det nya intervallet vara [pos+1, slut]
Det känns lite bakvänt då att skriva så här, ivf tycker jag det är lite svårt att läsa
else if (tal[pos] < nummer)
start = pos + 1;
else if (tal[pos] > nummer)
slut = pos - 1;
Kolla igenom programlogiken igen.
Blir det här mer rimligt? Det blir fortfarande fel när jag kör programmet av någon anledning. Det blir att jag exempelvis måste skriva in en 4 två gånger innan funktionen körs, kan det vara problemet?
Det verkar konstigt, kan du posta senaste koden (som kod) - så kan jag testköra hos mig.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define SIZE 100
#define N 10
void slumpTal( int tal[SIZE], size_t size )
{
int i= 0;
srand(time(NULL));
for(i = 0; i < SIZE; ++i)
{
tal[i] = rand() % 901;
}
for(i = 0; i < SIZE; i++) {
printf("%4d", tal[i]);
if(i % 10 == 9)
printf("\n");
}
}
void sort( int tal[SIZE], size_t size )
{
int i = 0;
int j = 0;
for (i = 0 ; i < SIZE; i++)
{
for (j = 0; j < SIZE - 1; j++)
{
if (tal[j] > tal[j+1])
{
int temp = tal[j];
tal[j] = tal[j+1];
tal[j+1] = temp;
}
}
}
for(i = 0; i < SIZE; i++) {
printf("%4d", tal[i]);
if(i % 10 == 9)
printf("\n");
}
}
void calculations(int tal[SIZE], size_t size) {
//max och min
int i = 0;
int max = 0;
int min = 900;
int summa = 0;
double medel = 0;
double median = 0;
for(i = 0; i < SIZE; i++){
if(tal[i] > max) {
max = tal[i];
}
if(tal[i] < min) {
min = tal[i];
}
}
//medelvärde
for(i = 0; i < SIZE; i++) {
summa += tal[i];
}
medel = summa / SIZE;
//median
median = (tal[49] + tal[50])/2;
printf("Max: %d Min: %d Medelvärde: %f Median: %f\n", max, min, medel, median);
}
void binsearch(int tal[SIZE], size_t size) {
//binärsökning
char buffer[100] = {0};
int i = 0;
int pos = 0; //position
int start = 0; //starposition i vektor
int slut = 99; //slutposition i vektor
int nummer = 0;
int flag;
int rad = 0; //rad
int kol = 0; //kolumn
printf("Skriv in ett nummer: \n");
fgets(buffer,sizeof(buffer),stdin);
sscanf(buffer, "%d", &nummer);
flag = 0;
while(start <= slut) {
pos = (start + slut)/2;
if(tal[pos] == nummer){
rad = (pos / N) + 1;
kol = (pos % N) + 1;
printf("Talet %d hittades på position %d samt på rad %d och kolumn %d\n", nummer, pos, rad, kol);
flag = 1;
break;
}
else if(tal[pos] > nummer)
start = pos - 1;
else if(tal[pos] < nummer)
slut = pos + 1;
break;
}
if(flag == 0)
printf("Talet finns ej\n");
}
void printMeny() {
//meny
printf("Meny\n");
printf("1. Generera en slumpgenerator\n");
printf("2. Sortera de genererade talen\n");
printf("3. Beräkna medelvärde, median samt max och min värde\n");
printf("4. Sök efter tal\n");
printf("0. Avsluta programmet\n");
}
int getNumber()
{
char buffer[100] = {0};
int number = -1;
if (fgets(buffer,sizeof(buffer),stdin)!=NULL)
{
if (sscanf(buffer, "%d", &number) == 1)
{
return number;
}
}
return -1;
}
int main()
{
int data[SIZE];
int val;
do
{
printMeny();
switch(getNumber()) {
case 0 :
break;
case 1 :
slumpTal( data, SIZE );
break;
case 2 :
sort( data, SIZE );
break;
case 3 :
calculations( data, SIZE);
break;
case 4 :
binsearch(data, SIZE);
break;
case -1 :
printf("Ogiltigt val\n");
break;
}
} while(getNumber() != 0);
return 0;
}
Jag ser ett fel i binsearch, du har ett extra break; i slutet på din while sats
while(start <= slut) {
...
break;
}
Det är därför den inte hittar något.
Jag brukar alltid använda { } runt alla mina if satser osv. även om det bara är en rad för det gör koden lättare att läsa, annars ibland kan det var lite knepigt att se om man råkar ta fel på indentation.
Anledningen till att den frågar två gånger är att du har två anrop till getNumber() i din do loop i main
do
{
printMeny();
switch(getNumber()) {
case 0 :
...
}
while (getNumber() != 0);
Ändra till
int val = 0;
do
{
printMeny();
switch(val = getNumber()) {
case 0 :
break;
...
} while(val != 0);
Byt också i binarySearch att läsa med getNumber istället.
Men du får kolla logiken i binarysearch, du får en oändlig loop där i vissa fall.
Du kan se det om du stoppar in ett putchar('.'); i loopen att det ideligen skrivs ut '.'
Skriv så här istället
else if(nummer < tal[pos]) {
slut = pos - 1;
}
else if(nummer > tal[pos]) {
start = pos + 1;
}
putchar('.');
Okej tack, nu funkar det. Men hur kommer det sig att det inte blir samma sak när man sätter val = getNumber()? Borde inte det bli samma resultat eftersom man istället har val 2 gånger?
När man skriver
switch (val = getNumber())
så sparas värdet i val, men hela uttrycket utvärderas också till val.
det är en detalj som man ivf förr i tiden ofta kunde göra fel på när man råka skriva
if (a = b + 1) // som alltid är sant
jfrt med
if (a == b + 1)
men nu förtiden är kompilatorerna smartare och man får minst en varning.
Varningar är mycket bra, men man ska först slå på dem och sedan också bry sig om dem.
Okej då fattar jag! Tack!