Gå til innhold

Problemer med å passe array til funksjoner i C


Anbefalte innlegg

Hei!

Når jeg kjører koden under får jeg av en eller annen grunn ikke tilgang til v[] elementene i sumfunksjonkoden, noe som vises ved at summen blir 0. Hvorfor?

Første gang jeg koder i C, men har kodet en del før. Sorry om det er et dumt spørsmål.

EDIT: tabbed meg ut ved å referere til v[n] istedenfor v :w00t:

#include <math.h>
#include <stdlib.h>
#include <stdio.h>

void fyllfunksjon(double v[], int n)
{
	for (int i = 1; i < n; ++i)
	{
		v[(i-1)] = 1/(pow(i,2));
	}
}

double sumfunksjon(double v[], int n, double sum)
{
	for (int i = 0; i < n-1; ++i)
		{
			sum = sum + v[n];
		}
	return sum;
}

int main()
{
	int k;
	int n;
	double sum;

		n = pow(2,2);
		double v[n];
		fyllfunksjon(v, n);
		sum = sumfunksjon(v, n, sum);
		printf("%f\n", sum);
}

Endret av PhelpsTransposed
Lenke til kommentar
Videoannonse
Annonse

Hvis du ønsker å fylle hele arrayen (4 elemementer) så må du endre i fyllfunksjon til:

    for (int i = 0; i < n; ++i)
    {
        v[i] = 1/(pow(i+1,2));
    }

og for å printe alle 4 elementene

for (int i = 0; i < n; ++i)

I C får uinitialiserte variabler tilfeldig verdi, endre "double sum;" til "double sum = 0;" for å initialisere sum til 0.

  • Liker 1
Lenke til kommentar

Takk for svar! Ett spørsmål til: med denne koden får jeg rett og slett ikke riktig sum. Sjekk den modifiserte, her får jeg sum på k = 14 på 1.423611, men dette er feil (http://www.wolframalpha.com/input/?i=sum+1%2Fn^2%2C+n%3D1+to+14)

Er det fordi jeg bruker double - ikke long?

#include <math.h>
#include <stdlib.h>
#include <stdio.h>

void fyllfunksjon(double v[], int n)
{
	for (int i = 1; i <= n; ++i)
	{
		v[(i-1)] = 1/(pow(i,2));
	}
}

double sumfunksjon(double v[], int n)
{
	double thesum = 0.0;
	for (int i = 0; i <= n; ++i)
		{
			thesum = thesum + v[i];
		}
	return thesum;
}

int main()
{
	int k = 0;
	int n = 0;
	double sum = 0;
	double S = pow(M_PI,2)/6;
	double difference;

	for (k = 3; k <= 14; ++k)
	{
		n = pow(2,2);
		double v[n-1];
		fyllfunksjon(v, n);
		sum = sumfunksjon(v, n);
		printf("%s %d\n", "The sum with k = ", k);
		printf("%f\n", sum);
		difference = S - sum;
		printf("%s\n", "S - Sn:");
		printf("%f\n", difference);

	}
}

Endret av PhelpsTransposed
Lenke til kommentar

Størelsen på v er n - 1.

 

Så hvis n er 4 kan v inneholde 3 elementer.

 

 

Begge for loopene dine skriver/leser utenfor arrayen.

 

fyllfunksjon vil skrive til v[0], v[1], v[2] og v[3] som er 1 utenfor arrayen.

Kan fikses ved å endre "<=" til "<".

 

 

sumfunksjon vil lese v[0], v[1], v[2], v[3] og v[4] som er 2 utenfor arrayen.

Kan fikses ved å endre til: for (int i = 0; i < n-1; i++);

Endret av Glutar
Lenke til kommentar

Oh boy. Her var det mye.

 

Er det fordi jeg bruker double - ikke long?

void fyllfunksjon(double v[], int n)
{
    for (int i = 1; i <= n; ++i)
    {
        v[(i-1)] = 1/(pow(i,2));
    }
}

 

Stil, men denne ville jeg forandret til:

void fill( double v[], int size ) {
    double *elem = v;
    for( int i = 1; i <= size; ++i, ++v )
        *v = 1.0 / ( i * i );
}
Disse gjør akkurat det samme. Siden du alltid skal kvadrere er det like greit å bruke i * i.

 

Her bruker jeg pointer arithmetic (vet du hva det er?), men du kan også bruke v[i-1] om du foretrekker det.

 

Dersom du bruker mitt eksempel må du bruke 1.0 og ikke 1, hvis ikke vil du bedrive heltallsdivisjon og få feil svar.

 

 

double sumfunksjon(double v[], int n)
{
    double thesum = 0.0;
    for (int i = 0; i <= n; ++i)
    {
        thesum = thesum + v[i];
    }
    return thesum;
}

 

Du har en logikk-feil i iterasjonen din. Du vil ha < n, ikke <= n. Husk at arrays er 0-indeksert i C. Mer stil:

double sum( const double v[], int size ) {
    const double *elem = v;
    double sum = 0;
    for( int i = 0; i < size; ++i, ++v )
        sum += *v;

    return sum;

Det er mange nifty måter å skrive dette på, men ingen grunn til å komplisere mer enn vi allerede har gjort. Men så til den store saken.

 

 

int main()
{
    int k = 0;
    int n = 0;
    double sum = 0;
    double S = pow(M_PI,2)/6;
    double difference;

    for (k = 3; k <= 14; ++k)
    {
        n = pow(2,2);
        double v[n-1];
        fyllfunksjon(v, n);
        sum = sumfunksjon(v, n);
        printf("%s %d\n", "The sum with k = ", k);
        printf("%f\n", sum);
        difference = S - sum;
        printf("%s\n", "S - Sn:");
        printf("%f\n", difference);

    }
}

 

Hvorfor har du rotet inn n her? Dette gjør at du kun jobber med de fire første elementene i hver sekvens, noe som gjør at summen din blir for liten. Om du inspiserer output vil du se at alle utregninger gir identisk svar. Fjern alle n og bytt ut med k, unntatt i arrayen. Det skal være v[ k ], ikke v[ k - 1 ]. Selv om du -aksesserer- med index-1 må størrelse fortsatt være så stor som du vil ha.

 

Ellers:

 

#1: int n = 0; n = pow( 2, 2 ). Hvorfor setter du ikke bare n = pow( 2, 2 ) med en gang? Den brukes jo aldri ellers.

#2: n er alltid 2² = 4. Hvorfor skriver du ikke bare 4?

#3: Kan du skrive C99? Flytt isåfall deklarasjonene inn til der du bruker de.

#4: printf( "%s\n", "S - Sn" ); printf( "%f\n", difference ) -> printf( "S - Sn\n%f\n", difference );

 

Resten skal jeg ikke pirke på med mindre du vil.

 

Foreslår følgende main:

 

int main() {
    const double S = pow(M_PI,2)/6;

    for ( int k = 3; k <= 14; ++k)
    {
        double v[ k ];
        fyllfunksjon(v, k);
        const double sum = sumfunksjon(v, k);
        printf( "Sum with k = %d: %f\n", k, sum );
        printf( "S - Sn: %f\n", S - sum );
    }
}

edit: hva i helvete er vitsen med code-tag hvis den ikke respekterer whitespace? skyt deg, ipb. Endret av Lycantrophe
Lenke til kommentar

Tusen takk for svar og hjelp! Skal gå gjennom og rette opp forslagene. Har såvidt kodet bitte bittelitt i C, og knapt noe i Fortran, ellers bare i C# og Java før så dette er veldig uvant.

Kan forklare noe rot først, jeg tok egentlig bort den k iterasjonen for å forsøke å løse problemet uten den først, og når jeg satt den tilbake så glemte jeg å ordne skikkelig. Riktig skal være:

n = pow(2,k);

i for-løkka i main. Ellers takk for svar, skal rydde opp. Vet ikke hva pointer arithmetic er, forresten.

Igjen, takk for at dere tok dere tid!

Lenke til kommentar

Wait. I wolframalpha-uttrykket ditt kjører du summe-funksjonen fra 1 -> k. Hvorfor skal du plutselig summere til chart?cht=tx&chl=2^{k}?

 

--

 

En peker i C er egentlig en helt vanlig verdi, altså et tall. Pekeraritmetikk er som "vanlig" aritmetikk, men med peker-verdier i stedet.

 

Her er det viktig å huske på at en array oppfører seg som en peker. Hvorfor dette er unyansert og ikke helt riktig er en lang og komplisert diskusjon, så dette går vi ikke inn på. Uansett, i dette tilfellet så kan du se på array-verdien som en peker til det første elemenetet. Fordi kompilatoren din vet at alle elementer har verdien double (aka den vet størrelsen på hvert element i arrayen) vil ++pointer gjøre at pointeren peker på ett element til høyre.

 

I dette tilfellet er det mest stil. Jeg har ikke sansen for å aksessere en array med offset når du uansett skal gjennom hele, selv om en smart nok™ kompilator klarer å optimalisere det bort.

 

Vet du hva en iterator er? Mener at C# har slikt.

Lenke til kommentar

 

 

        v[(i-1)] = 1/(pow(i,2));

 

Den store feilen er likevel at du driver heltallsdivisjon (integer division). Som du ser har jeg forandret 1 -> 1.0. Dette gir deg mellomresultatene du vil ha.

 

I din versjon må man nok bruke 1.0. I den opprinnelige versjonen er resultatet av en 1/pow(...) en double og det foregår ikke heltallsdivisjon (med forbehold om at jeg misforstod hva kommentaren refererte til)

Endret av zotbar1234
Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...