34 svar
413 visningar
erze7811 102
Postad: 29 nov 2022 19:57

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?

erze7811 102
Postad: 29 nov 2022 19:58

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.

anders_k 234
Postad: 29 nov 2022 20:44 Redigerad: 29 nov 2022 20:45

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);
Laguna 28468
Postad: 29 nov 2022 20:48

Använd aldrig scanf. Läs in en rad i taget och använd sscanf.

anders_k 234
Postad: 29 nov 2022 20:51 Redigerad: 29 nov 2022 20:51

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

erze7811 102
Postad: 29 nov 2022 20:55 Redigerad: 29 nov 2022 20:56

Vad är det för skillnad mellan sscanf och scanf? och hur implemeterar jag det?

anders_k 234
Postad: 29 nov 2022 21:01
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");
  }
}
erze7811 102
Postad: 29 nov 2022 21:19

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

anders_k 234
Postad: 29 nov 2022 23:55 Redigerad: 29 nov 2022 23:57

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)
{
  ...
} 
erze7811 102
Postad: 30 nov 2022 09:09 Redigerad: 30 nov 2022 09:11

Hur ser detta ut?

första bilden är i main()

anders_k 234
Postad: 30 nov 2022 20:34 Redigerad: 30 nov 2022 20:41

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]...
}

 

 

 

erze7811 102
Postad: 2 dec 2022 18:36

blir detta rätt?

erze7811 102
Postad: 2 dec 2022 18:55

Det blir fel fortfarande fel

erze7811 102
Postad: 2 dec 2022 20:45

< printf()>

anders_k 234
Postad: 3 dec 2022 00:02

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;
}
erze7811 102
Postad: 3 dec 2022 17:20

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?

Laguna 28468
Postad: 3 dec 2022 17:45

buffer är lite liten. Det kanske är därför.

Du hade nåt som hette SIZE förut.

erze7811 102
Postad: 3 dec 2022 17:50

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

Laguna 28468
Postad: 3 dec 2022 18:14

Jag ser inte vad som är fel. Stoppa in printf här och där i getnumber så vi ser vad som händer.

erze7811 102
Postad: 3 dec 2022 18:34
#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
erze7811 102
Postad: 3 dec 2022 18:34

Nu står det error number undeclared när jag kör programmet, vart ska jag lägga in printf?

Laguna 28468
Postad: 3 dec 2022 18:53

I funktionen, inte i anropet.

erze7811 102
Postad: 3 dec 2022 19:04

Såhär? Blir samma resultat

erze7811 102
Postad: 3 dec 2022 20:45

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;    
}
anders_k 234
Postad: 3 dec 2022 21:47 Redigerad: 3 dec 2022 21:58

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.

erze7811 102
Postad: 4 dec 2022 12:59

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.

anders_k 234
Postad: 4 dec 2022 15:34 Redigerad: 4 dec 2022 15:38

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.

erze7811 102
Postad: 5 dec 2022 12:02

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?

anders_k 234
Postad: 5 dec 2022 13:16 Redigerad: 5 dec 2022 13:16

Det verkar konstigt, kan du posta senaste koden (som kod) - så kan jag testköra hos mig.

erze7811 102
Postad: 5 dec 2022 14:13
#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;    
}
anders_k 234
Postad: 5 dec 2022 15:25 Redigerad: 5 dec 2022 16:59

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('.');
erze7811 102
Postad: 5 dec 2022 22:26

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?

anders_k 234
Postad: 6 dec 2022 14:32

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.

Laguna 28468
Postad: 6 dec 2022 14:35

Varningar är mycket bra, men man ska först slå på dem och sedan också bry sig om dem.

erze7811 102
Postad: 6 dec 2022 19:15

Okej då fattar jag! Tack!

Svara Avbryt
Close