Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C: Kokonaisluvun pilkkominen

Sivun loppuun

punppis [07.09.2007 23:14:40]

#

Millä konstilla saisi kokonaisluvun pilkottua yksittäisiksi luvuiksi?

Esim.
int luku = 673; <- tuosta tulisi seuraava muuttuja: osat[0] = 6, osat[1] = 7, osat[2] = 3.

Antti Laaksonen [07.09.2007 23:35:13]

#

Seuraava koodi toimii positiivisilla kokonaisluvuilla ja nollalla. Jos luku onkin negatiivinen, voit muuttaa sen ensin vastaluvuksi. Ensin selvitetään luvun pituus katsomalla, mikä on suurin luvun 10 moninkerta, joka on lukua pienempi tai sen kanssa yhtä suuri. Esim. jos luku on 673, viimeinen tällainen moninkerta on 100, joten luvussa on kolme numeroa. Tämän jälkeen haetaan luvun numerot yksi kerrallaan jakamalla sitä toistuvasti 10:llä ja ottamalla talteen jakojäännökset. Tällä menetelmällä numerot tulevat käänteisessä järjestyksessä, minkä vuoksi oli hyvä tietää niiden määrä etukäteen, jotta numerot saadaan suoraan oikeaan paikkaan taulukossa.

int luku = 673;
int osat[20];
int pituus = 1;
int laskuri = 10;
/* selvitetään numeroiden määrä */
while (laskuri <= luku) {
    pituus++;
    laskuri *= 10;
}
/* haetaan numerot taulukkoon */
laskuri = pituus - 1;
while (laskuri >= 0) {
    osat[laskuri] = luku % 10;
    luku /= 10;
    laskuri--;
}
/* näytetään määrä ja numerot */
printf("Luvussa on %i numeroa:\n", pituus);
for (laskuri = 0; laskuri < pituus; laskuri++) {
    printf("%i\n", osat[laskuri]);
}

tgunner [07.09.2007 23:45:01]

#

tai sit superkäytännöllisemmin:

int luku;
char tmp[10];
luku=673;
itoa(luku,tmp,10); /* kymmenjärjestelmään */
printf("%c %c %c",tmp[0],tmp[1],tmp[2]);

kayttaja-2499 [08.09.2007 00:00:06]

#

Myöhästyin :(.
Esitän oman ratkaisuni kuitenkin kun se tuli tehtyä ja testattua:

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

int main(int argc, char **argv) {
        int luku = 673;
        int n = log10(luku)+1;
        int *osat;
        int tmp = luku;
        int i;

        osat = malloc(n*sizeof(int));

        for(i = n-1; i >= 0; i--) {
                osat[i] = tmp%10;
                tmp /= 10;
        }

        printf("%d\n", luku);
        for(i = 0; i < n; i++) {
                printf("%d\n", osat[i]);
        }

        free(osat);

        return 0;
}

punppis [09.09.2007 19:34:29]

#

tqunnerin vinkki ei oikeen toiminut. Antin koodi taas toimi vallan mainoisti. Kiitos!

Gaxx [09.09.2007 19:47:41]

#

punppis kirjoitti:

tqunnerin vinkki ei oikeen toiminut.

Mikähän tqunnerin vinkissä ei toiminut? Itselläni pelitti ainakin. Itoa-funktio löytyy ainakin stdlib.h-otsikkotiedostosta.

FooBat [09.09.2007 19:50:43]

#

Siinä ei varmaan toiminut se, että luvuista tuli merkkejä eikä lukuja.

Pekka Karjalainen [09.09.2007 20:31:10]

#

Koska minulla oli tähän liittyvää koodia, tarjoan omankin version. Tämä näyttää, miten tuon väärän järjestyksen ongelman voi kiertää rekursion avulla luontevasti. On tietenkin aivan laillista pitää iteratiivisista ratkaisuista tällaisen sijasta, mutta minä puolestani tykkään tästä.

Rekursio sopii tähän käyttöön, koska int-tyyppisen muuttujan koko on rajoitteinen. Ei tarvitse huolehtia, että tulee liian monta perättäistä kutsua.

Käytän -1:stä etumerkkitietona, ja se siis löytyy negatiivisen luvun numerolistan alusta.

#include <stdio.h>

#define MAX_DIGITS 20 /* 20 digits in 2^64 */
#define END_DIGITS -2 /* marks the end of the array, -1 and 0 N.A. */

int* get_digits_rec (int n, int* out) {
	int last_digit = n % 10;
	int rest = n / 10;
	if (rest > 0) out = get_digits_rec (rest, out);
	*out++ = last_digit;
	return out;
}

void get_digits (int n, int buf[MAX_DIGITS+2]) {
	int* out = buf;
	if (n < 0) {
		n *= -1;
		*out++ = -1;
	}
	out = get_digits_rec (n, out);
	*out = END_DIGITS;
}

void test_it (int n) {
	int i=0;
	int digits [MAX_DIGITS+2];
	printf ("Testing with %10d: ", n);
	get_digits (n, digits);
	printf ("[");
	while (digits[i] != END_DIGITS) {
		printf ("%d", digits[i]);
		++i;
		if (digits[i] != END_DIGITS)
			printf (", ");
	}
	printf ("]\n");
}

int main (void) {
	test_it (3);
	test_it (33);
	test_it (333);
	test_it (123456789);
	test_it (-1);
	test_it (-12);
	test_it (-123);
	test_it (0);
	return 0;
}

Metabolix [09.09.2007 20:54:49]

#

No kun nyt kerran toteutuksia laitetaan näytille, niin laitanpa minäkin printf-funktiota varten tekemäni:

#define UINTMAX_DIGITS 20

/* Etumerkitön */
char *fmtuint(uintmax_t i, char *buf_end)
{
    *--buf_end = 0; // Tekstin lopetus;
    while (i) {
        *--buf_end = (i%10) + '0';
        i /= 10;
    }
    return buf_end;
}

/* Etumerkillinen */
char *fmtint(intmax_t i, char *buf_end)
{
    if (i < 0) {
        buf_end = fmtuint(-i, buf_end);
        *--buf_end = '-';
        return buf_end;
    }
    return fmtuint(i, buf_end);
}
char puskuri[UINTMAX_DIGITS + 2];
char *teksti;
teksti = fmtint(-123456, puskuri + sizeof(puskuri));
printf("%d = %s\n", -123456, teksti);
/* Ja se int-tauluksi muuttaminen, jos pitää tuota kautta tehdä */
/* Etumerkkiä ei nyt huomioida tässä. */
int numerot[UINTMAX_DIGITS];
int i;
for (i = 0; teksti[i]; ++i) {
    numerot[i] = teksti[i] - '0';
}

Pekka Karjalainen [10.09.2007 10:21:23]

#

Metabolix kirjoitti:

char puskuri[UINTMAX_DIGITS + 2];
char *teksti;
teksti = fmtint(-123456, puskuri + sizeof(puskuri));
printf("%d = %s\n", teksti);

Metabolixin tapa kääntää numerot oikeinpäin on myös selkeä, jos minulta kysytään.

On ehkä vähän epähienoa tästä nyt nipottaa, mutta tuossa taisi mennä parametrit ja %-liput vahingossa vähän ristiin:

printf("%d = %s\n", teksti);

Vai onko minulla näin aamusta vielä silmät ristissä?

Metabolix [10.09.2007 19:01:50]

#

Kopeekka kirjoitti:

On ehkä vähän epähienoa tästä nyt nipottaa, mutta tuossa taisi mennä parametrit ja %-liput vahingossa vähän ristiin.

Huppeliskeikkaa, jäi se luku printtaamatta. :) Korjasinpa.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta