Ir para o conteúdo

Conversão de uma string para um array de int

Quando temos um número numa string, por vezes, pode ser prático passar os dígitos desse número para um array de int. A maneira mais prática de o fazer é, sem dúvida, uma cópia "directa" da string para o array.

while (*src) *dst++ = *src++ - '0';

Mas esta solução prática pressupoe duas coisas que podem não ser verdade em alguns casos.

  • src é composto unicamente por digitos (e o \0)
  • dst tem espaço suficiente para todos os dígitos de src.

A função que se segue evita os erros quando os pressupostos não são verdade, fiz uma função que passa os dígitos duma string para um array de int.

  • A função atoarr() copia os digitos duma string para um array de int.
    atoarr(array, 10, "1415926535"); /* array[0] = 1; array[1] = 4; ... array[9] = 5; */
    
  • Os caracteres que não sejam dígitos são ignorados.
    atoarr(array, 2, " 3\n"); /* array[0] = 0; array[1] = 3; */
    
  • Se houver vários grupos de dígitos, só o primeiro grupo é considerado.
    atoarr(array, 4, "abc123def456ghi"); /* array[0] = 0; array[1] = 1; array[2] = 2; array[3] = 3; */
    
  • O tamanho do array de destino também é tido em conta e nunca será escrito nada fora do array.
  • Se a string tiver poucos dígitos para o array, os elementos extra são preenchidos com 0.
    atoarr(array, 4, "42"); /* array[0]=0; array[1]=0; array[2]=4; array[3]=2; */
    
  • Se a string tiver muitos dígitos só os dígitos menos significativos é que são copiados para o array.
    atoarr(array, 2, "8542"); /* array[0]=4; array[1]=2; */
    

Ficheiro: atoarr.h

#ifndef ATOARR_H_INCLUDED
#define ATOARR_H_INCLUDED

/* atoarr: 'converts' a string into an array of int
 *         the function ignores all characters that are not digits
 *         but only considers the first group of digits for the conversion
 *
 * Parameters:
 *     int *arr        ==> the destination array
 *     int elems       ==> number of elements in the destination array
 *     const char *src ==> the source string
 * All consecutive digits in `src` are put into arr
 * Return value:
 *     ATOARR_OK (0)
 *       all ok
 *       some characters in `src` may not be digits or whitespace
 *     ATOARR_SMALL (1)
 *       arr is too small for all digits in src
 *       the least significant digits are copied
 *     ATOARR_NODIGITS (2)
 *       no digits in src
 *       the destination array is filled with 0's
 *     ATOARR_NULL (-1)
 *       `src` or `arr` are NULL
 *     ATOARR_NOELEMS (-2)
 *       elems < 1
 */

enum ATOARR_CODES {
  ATOARR_NOELEMS = -2, /* elems < 1 */
  ATOARR_NULL,         /* src or arr is NULL*/
  ATOARR_OK,           /* all ok */
  ATOARR_SMALL,        /* arr is too small */
  ATOARR_NODIGITS      /* no digits in src */
};

int atoarr(int *arr, int elems, const char *src);

#endif

Ficheiro: atoarr.c

#include <ctype.h>
#include "atoarr.h"

int atoarr(int *arr, int elems, const char *src) {
  int ndx = 0;                  /* for indexing src first, then arr */
  int ndigits;                  /* number of consecutive digits in src */
  int first_unused_digit;       /* position of first unused digit in src */
                                /* a digit becomes 'used' after it's been converted and copied to arr */
  int small_arr_adjustment = 0; /* needed for when arr is not large enough for all digits in src */
  int opt_tmp;                  /* optimize subtraction away from the loop */
  int retval = ATOARR_OK;       /* value to return to caller */

  /* validate inputs */
  if (!src || !arr) { return ATOARR_NULL; }
  if (elems < 1) { return ATOARR_NOELEMS; }

  /* skip initial non digits */
  while (src[ndx] && !isdigit((unsigned char)src[ndx])) { ndx++; }

  first_unused_digit = ndx;
  /* count consecutive digits */
  ndigits = 0;
  while (isdigit((unsigned char)src[ndx])) { ndigits++; ndx++; }
  /* if there are special circunstances, set retval */
  if (ndigits > elems) { retval = ATOARR_SMALL; }
  if (ndigits == 0) { retval = ATOARR_NODIGITS; }

  /* fill the first 'unused' elements with 0 */
  ndx = 0; /* re-use ndx */
  opt_tmp = elems - ndigits; /* help the compiler optimize the subtraction away :) */
  while (ndx < opt_tmp) {    /* while (ndx < elems - ndigits) { */
    arr[ndx] = 0;
    ndx++;
  }

  /* adjust index if arr is too small */
  if (elems < ndigits) { small_arr_adjustment = ndigits - elems; }
  /* convert and copy digits */
  while (ndx < elems) {
    arr[ndx] = src[first_unused_digit + small_arr_adjustment] - '0';
    first_unused_digit++;
    ndx++;
  }

  return retval;
}

Exemplo de uso

#include <stdio.h>
#include "atoarr.h"

int main(void) {
  const char *num;
  int array[20];
  int k, arr_size;
  int val;

  num = "      1234567890123456789      ";
  arr_size = 20;
  val = atoarr(array, arr_size, num);
  printf("[%s] ==> ", num);
  if (val >= ATOARR_OK) for (k=0; k<arr_size; k++) printf("%d ", array[k]);
  printf("(return value: %d)\n", val);

  num = "      1234567890123456789      ";
  arr_size = 12;
  val = atoarr(array, arr_size, num);
  printf("[%s] ==> ", num);
  if (val >= ATOARR_OK) for (k=0; k<arr_size; k++) printf("%d ", array[k]);
  printf("(return value: %d)\n", val);

  num = "42";
  arr_size = 6;
  val = atoarr(array, arr_size, num);
  printf("[%s] ==> ", num);
  if (val >= ATOARR_OK) for (k=0; k<arr_size; k++) printf("%d ", array[k]);
  printf("(return value: %d)\n", val);

  num = "0";
  arr_size = 6;
  val = atoarr(array, arr_size, num);
  printf("[%s] ==> ", num);
  if (val >= ATOARR_OK) for (k=0; k<arr_size; k++) printf("%d ", array[k]);
  printf("(return value: %d)\n", val);

  num = "";
  arr_size = 6;
  val = atoarr(array, arr_size, num);
  printf("[%s] ==> ", num);
  if (val >= ATOARR_OK) for (k=0; k<arr_size; k++) printf("%d ", array[k]);
  printf("(return value: %d)\n", val);

  num = "2008-December-10";
  arr_size = 6;
  val = atoarr(array, arr_size, num);
  printf("[%s] ==> ", num);
  if (val >= ATOARR_OK) for (k=0; k<arr_size; k++) printf("%d ", array[k]);
  printf("(return value: %d)\n", val);

  num = "pmg";
  arr_size = 6;
  val = atoarr(array, arr_size, num);
  printf("[%s] ==> ", num);
  if (val >= ATOARR_OK) for (k=0; k<arr_size; k++) printf("%d ", array[k]);
  printf("(return value: %d)\n", val);

  num = "60 something";
  arr_size = 6;
  val = atoarr(array, arr_size, num);
  printf("[%s] ==> ", num);
  if (val >= ATOARR_OK) for (k=0; k<arr_size; k++) printf("%d ", array[k]);
  printf("(return value: %d)\n", val);

  num = "RS232-C";
  arr_size = 6;
  val = atoarr(array, arr_size, num);
  printf("[%s] ==> ", num);
  if (val >= ATOARR_OK) for (k=0; k<arr_size; k++) printf("%d ", array[k]);
  printf("(return value: %d)\n", val);

  num = NULL;
  arr_size = 6;
  val = atoarr(array, arr_size, num);
  printf("[NULL] ==> ");
  if (val >= ATOARR_OK) for (k=0; k<arr_size; k++) printf("%d ", array[k]);
  printf("(return value: %d)\n", val);

  num = "2008";
  arr_size = 1;
  val = atoarr(NULL, arr_size, num);
  printf("[%s] ==> ", num);
  if (val >= ATOARR_OK) for (k=0; k<arr_size; k++) printf("%d ", array[k]);
  printf("(return value: %d)\n", val);

  num = "2008";
  arr_size = 0;
  val = atoarr(array, arr_size, num);
  printf("[%s] ==> ", num);
  if (val >= ATOARR_OK) for (k=0; k<arr_size; k++) printf("%d ", array[k]);
  printf("(return value: %d)\n", val);

  num = "2008";
  arr_size = 1;
  val = atoarr(array, arr_size, num);
  printf("[%s] ==> ", num);
  if (val >= ATOARR_OK) for (k=0; k<arr_size; k++) printf("%d ", array[k]);
  printf("(return value: %d)\n", val);

  return 0;
}

Resultado do teste

[      1234567890123456789      ] ==> 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 (return value: 0)
[      1234567890123456789      ] ==> 8 9 0 1 2 3 4 5 6 7 8 9 (return value: 1)
[42] ==> 0 0 0 0 4 2 (return value: 0)
[0] ==> 0 0 0 0 0 0 (return value: 0)
[] ==> 0 0 0 0 0 0 (return value: 2)
[2008-December-10] ==> 0 0 2 0 0 8 (return value: 0)
[pmg] ==> 0 0 0 0 0 0 (return value: 2)
[60 something] ==> 0 0 0 0 6 0 (return value: 0)
[RS232-C] ==> 0 0 0 2 3 2 (return value: 0)
[NULL] ==> (return value: -1)
[2008] ==> (return value: -1)
[2008] ==> (return value: -2)
[2008] ==> 8 (return value: 1)