Vinnaren i pepparkakshustävlingen!
2017-11-21, 14:18
  #1
Medlem
smellyproofs avatar
Jag har en fungerande kod och allt funkar som det ska. Men ett krav för uppgiften är att det inte får innehålla några "globala variabler". Min kod innehåller bara det tror jag. Vet inte riktigt hur jag ska få till det för gör man bara lokala variabler finns det ju bara i sin funktion och problemet är att jag använder flera funktioner, som man ska göra, då verkar det vara bättre att ha färre globala variabler än flera lokala? Vet inte riktigt hur de har tänkt.

Uppgift:


Kod:
Kod:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int tal[99] = {-1};
int bubbles,byte, c, d, val;

/* Funktion för talföljd*/
int talserie(){
srand ( time(NULL) );
for(c = 0; c < 100; c++){

tal[c] = rand() % 901;
printf(" %d ", tal[c]);

if ((c+1) % 10 == 0)
printf("\n");}
}
/* Funktion för bubbelsortering*/
int bubbel(){
 for (c = 0 ; c < ( 99 ); c++)
  {
    for (d = 0 ; d < 99 - c ; d++)
    {
      if (tal[d] > tal[d+1]) 
      {
        byte       = tal[d];
        tal[d]   = tal[d+1];
        tal[d+1] = byte;
      }
    }
}

  for ( c = 0 ; c < 100 ; c++ ){
     printf(" %d ",  tal[c]);
if ((c+1) % 10 == 0)
printf("\n");
}
}

/* Funktion för median-, max/min- och medelvärde*/
int varde(){
printf("\nMaxvärdet är: %d", tal[99]);
printf("\nMinvärdet är: %d", tal[0]);

int total = 0;
 for ( c = 0 ; c < 100 ; c++ )   {
total = total + tal[c];
}

printf("\nMedelvärdet är: %d", total/100);
printf("\nMedianvärdet är: %d", ((tal[49] + tal[50]) / 2));
}

/*Funktion leta siffra*/
int siffra(){
printf("\nSkriv in en siffra: ");
scanf("%d", &val);
d = 0;
for( c = 0 ; c < 100 ; c++){
if(tal[c]== val){
d = 1;
printf("\nFinns i talföljden på plats: ");
if(c <= 9)
printf(" Rad 1 och Kolumn %d\n", c +1);
else if (c > 9 && c <= 19)
printf(" Rad 2 och Kolumn %d\n", (c +1) - 10);
else if (c > 19 && c <= 29)
printf(" Rad 3 och Kolumn %d\n", (c +1) - 20);
else if (c > 29 && c <= 39)
printf(" Rad 4 och Kolumn %d\n", (c +1) - 30);
else if (c > 39 && c <= 49)
printf(" Rad 5 och Kolumn %d\n", (c +1) - 40);
else if (c > 49 && c <= 59)
printf(" Rad 6 och Kolumn %d\n", (c +1) - 50);
else if (c > 59 && c <= 69)
printf(" Rad 7 och Kolumn %d\n", (c +1) - 60);
else if (c > 69 && c <= 79)
printf(" Rad 8 och Kolumn %d\n", (c +1) - 70);
else if (c > 79 && c <= 89)
printf(" Rad 9 och Kolumn %d\n", (c +1) - 80);
else if ( c > 89 && c <= 99)
printf(" Rad 10 och Kolumn %d\n", (c +1) - 90);
break;
}
}
if (d == 0);
{
printf("\n%d Finns inte i talföljden", val);
}
}
/* Main funktion med switch meny*/
int main()
{
while(val != 5) {
printf("\n1. Generera en talföljd med 100 tal mellan 0-900.");
printf("\n2. Sortera talföljden i storleksordning.");
printf("\n3. Räkna ut medelvärde, median och maxvärde.");
printf("\n4. Sök efter valfritt tal.");
printf("\n5. För att avsluta\n");
printf("Skriv in ett val (1-5): ");



scanf("%d", &val);

switch(val){

case 1:
talserie();
break;

case 2:
if(tal[0] == -1)
printf("\nFel! Generera en talföljd först!\n");
else
bubbel();
break;

case 3:
if(tal[0] == -1) /* Arrayen innehåller -1 i [0] innan talföljden genereras"*/
printf("\nFel! Generera en talföljd först!\n");
else if (tal[0] <= tal[1] && tal[1] <= tal[2] && tal[2] <= tal[3]) /* Om tal[0] <= tal[1] och tal[1] <= tal[2] och tal[2] < tal[3] så har talföljden sorterats*/
varde();
else
printf("\nFel! Sortera talföljden i storleksordning först!\n");
break;

case 4:
if(tal[0] == -1) 
printf("\nFel! Generera en talföljd först!\n");
else if (tal[0] <= tal[1] && tal[1] <= tal[2] && tal[2] <= tal[3])
siffra();
else
printf("\nFel! Sortera talföljden i storleksordning först!\n");
break;

}
}
return 0;
}
__________________
Senast redigerad av smellyproof 2017-11-21 kl. 14:21.
Citera
2017-11-21, 19:34
  #2
Medlem
Lägg variabeln tal i funktion main. Den ska för övrigt vara tal[100] istället för tal[99], i annat fall får det inte plats 100 tal. Låt därefter de olika funktionerna få med tal och storleken på tal (100) som argument.

Exempel: funktion talserie blir istället "int talserie(int* pTal, int iSize).

Variablerna c, d, byte och val kan göras lokala i respektive funktion. Det går utmärkt att använda samma variabel-namn, till exempel c, i flera olika funktioner. Dessa blir då olika variabler trots att de har samma namn. Du använder redan en lokal variabel total i funktionen varde. Gör på motsvarande sätt med de andra variablerna.

Funktionen talserie skulle då kunna se ut på följande sätt:
/* Funktion för talföljd*/
int talserie(int* pTal, int iSize){
int c, d;
srand ( time(NULL) );
for(c = 0; c < iSize; c++){

pTal[c] = rand() % 901;
printf(" %d ", pTal[c]);

if ((c+1) % 10 == 0)
printf("\n");}
}

Från main ser anrop till talserie ut på följande sätt:
talserie(tal, 100);

Se över dina start- och stoppvärden för variabler och kontrollera om det ska vara 99 (numera iSize - 1) eller 100 (numera iSize).

Lycka till med detta projekt.
Citera
2017-11-21, 20:16
  #3
Avstängd
Citat:
Ursprungligen postat av smellyproof
Jag har en fungerande kod och allt funkar som det ska. Men ett krav för uppgiften är att det inte får innehålla några "globala variabler". Min kod innehåller bara det tror jag. Vet inte riktigt hur jag ska få till det för gör man bara lokala variabler finns det ju bara i sin funktion och problemet är att jag använder flera funktioner, som man ska göra, då verkar det vara bättre att ha färre globala variabler än flera lokala? Vet inte riktigt hur de har tänkt.

Prova flytta en av funktionerna till en annan fil i programmet eller återanvända den i ett annat program. Tror inte att du kommer ihåg om två veckor vilka globala variabler funktionen är beroende av, som alltså måste flyttas med tillsammans med den. Och det blir krångligt om någon av deras namn krockar med namnet på en global variabel en annan funktion i den nya filen/programmet använder.

En funktion som bara har tillgång till det data den ska läsa/skriva, via dess argument och returvärde, är lätt att flytta och lätt att förstå. Den har också mindre risk att bugga (ju fler kockar på samma soppa) och när det ändå buggar är det lättare att hitta felet.

https://sv.wikipedia.org/wiki/Funktionell_programmering
Citera
2017-11-21, 20:37
  #4
Medlem
smellyproofs avatar
Citat:
Ursprungligen postat av BajenLeeds
text
Tack för din input och att du klargjorde vilka variabler som måste vara globala. För även om det står inga "globala variabler" så måste ju talföljden vara global känner jag.

Angående tal[99] så innehåller den 100 element för att c börjar räkna element i en array på [0].
Citera
2017-11-21, 20:54
  #5
Medlem
guderis avatar
Citat:
Ursprungligen postat av smellyproof
Tack för din input och att du klargjorde vilka variabler som måste vara globala. För även om det står inga "globala variabler" så måste ju talföljden vara global känner jag.

Angående tal[99] så innehåller den 100 element för att c börjar räkna element i en array på [0].

Det fetade. Nja du tänker fel där. Det är sant att c börjar räkna index med 0, men vill du ha en array med 100 element så skriver du tal[100] och den kommer då gå från index 0-99.
Citera
2017-11-21, 22:50
  #6
Avstängd
Citat:
Ursprungligen postat av smellyproof
För även om det står inga "globala variabler" så måste ju talföljden vara global känner jag.

Du känner rätt. I C är funktionsanrop alltid call-by-value, vilket innebär att en lokal kopia skapas av varje argument. Att kopiera en hundra miljoner element lång array varje gång man anropar en funktion är inte så bra för prestandan, så man skickar en pekare. Pekaren, ett adressvärde på typ 4 byte (beror på systemet), kopieras så det är fortfarande call-by-value. Men datat som finns på adressen kopieras inte.

Arrayer går inte ens att skicka mellan funktioner, för C är ett snabbt lågnivåspråk och tio tecken av kodtext ska inte kunna uppehålla processorn i två minuter. Om inte den där korta kodtexten har ett funktionsanrop, men då förväntas det att man vet hur lång tid funktionen kan ta. Jämför med andra språk där en operation som `string1 + string2` kan ta jättelång tid. I C kan string1 och string2 bara vara värden på några byte och operationen går på nolltid. Om de är pekare, fortfarande på bara några byte, är operationen säkert inte vad du vill göra (addera en adress till en annan) och kompilatorn kommer att varna eller vägra att kompilera koden. Du lär skicka adresserna till en funktion istället, t.ex. strcat() som slår ihop strängar.

För att få adressen till en variabel använder man operatorn &, och för att få värdet som en adress pekar på använder man operatorn *. De är varandras motsatser. Eller... * är inte bara för att få värdet, utan kunna sätta det också. Om pekarvariabeln x innehåller adressen till Bill Gates banksaldo, kan du göra honom pank med `*x = 0;`.

Tyvärr finns det en lite ologisk regel som nybörjare faller på. Arrayer går som sagt inte att behandla som en enda enhet, t.ex. addera med +, jämföra med ==, tilldela med = eller skicka till/returnera från en funktion. Man jobbar alltid med adressen till arrayen. Men arraynamn behöver ändå inte adressoperatorn & före, för namnet omvandlas automatiskt till adressen till arrayens första element, både inom en funktions kod och i dess argumentlista.

Kod:
void doSomethingWith(int listOfNumbers[]) {
    /* listOfNumbers är inte funktionens privata kopia, utan en pekare till originalarrayen */
}

Anyway...

För att datat är globalt på det sättet att det bara finns en kopia av det i minnet, behöver det inte nödvändigtvis vara namngivet m.h.a. en global variabel. Utrymmet för det kan allokeras med malloc(), som returnerar en pekare till det, eller NULL om minnet tog slut. Och pekaren är som sagt bara på några byte, tar knappt något minne och kan skickas snabbt mellan anropande och anropad funktion.

Deklarera gärna pekare som pekare-till-const om den anropade funktionen bara ska läsa ur arrayen, så får du lite extra säkerhet. Kompilatorn kollar då att funktionen inte någonstans försöker skriva till den. Det kan den göra under själva kompilationen så det förändrar inte programmet eller gör det långsammare.
__________________
Senast redigerad av B-programmerare 2017-11-21 kl. 22:54.
Citera

Stöd Flashback

Flashback finansieras genom donationer från våra medlemmar och besökare. Det är med hjälp av dig vi kan fortsätta erbjuda en fri samhällsdebatt. Tack för ditt stöd!

Stöd Flashback