Ash
Ash

Reputation: 21

Reading Integers From A Buffer into an Array in C

So I'm trying to store int values that have been read from the keyboard into an array of integers in C. Sample user input:

8 99 5 7 8

variable declarations:

int k;
int size;
char buf[100];

The above is my buffer and other variables for the array. The below is to read the ints into the buffer.

printf("Please enter in the numbers for the array:\n");
fgets(buf, 100, stdin);
buf[strlen(buf) - 1] = '\0';

size = (strlen(buf)/2)+1;

int *array = (int *)malloc(sizeof(int)*size);

So that correctly allocates my array.

int i, j;
for(i = 0, j = 0; i < size; i++, j = j+2)
{
    array[i] = buf[j] - '0';
}

The above code actually works, but not for numbers that have double digits, only for numbers below 10 and above 0. How can I fix my code so that I correctly read in the integers? I have tried to do a for loop with sscanf, but that just leads to an array with only the first integer entered in all elements.

Upvotes: 1

Views: 3564

Answers (4)

user3386109
user3386109

Reputation: 34839

You can use sscanf or strtol to extract the numbers from the input string. In either case, you will be given three pieces of information from each call:

  • an indication that a valid number was found
  • the value of that number
  • the location in the input array where the next number will be found

With sscanf, the return value indicates success or failure. For the sscanf in the sample code (see below), the return value is 1 for success, anything else is a failure. If successful, the value of the number is placed at the address specified, e.g. &temp in the sample code.

And here's the tricky part: you need the location in the array to start the search for the next number. sscanf has a special conversion for that, the %n conversion. The output from %n is the number of characters that were consumed while performing the conversion(s).

In the sample code below, I use a pointer ptr that initially points to the beginning of the input string. On each pass through the loop, %n is used in the sscanf to update variable n, which indicates how many characters were consumed converting the current number. By adding n to ptr in the for loop, the pointer is advanced to the next number.

int *array = malloc(sizeof(int) * size);
int n = 0;
int i = 0;
for ( char *ptr = buf; *ptr; ptr += n )
{
    int temp;
    if ( sscanf(ptr, "%d %n", &temp, &n) != 1 ) {
        // error: not a number
        break;
    }
    array[i++] = temp;
}

As mentioned by @chux in the comments, adding a space to the format string "%d %n" will consume trailing whitespace after each number and set the value of n accordingly. Thus, if the input line contains only numbers, the loop will end when the for statement detects that *ptr has reached the NUL terminator. But if the input contains a non-number, then the loop will break when the sscanf fails. This can be used for error checking.

Upvotes: 1

dreamlax
dreamlax

Reputation: 95355

If the numbers are coming from stdin, it's more effort to read them in as a string and convert them yourself than it is to have the standard library do it for you. Here I've hardcoded a maximum number of 100 integers. After the loop, i will represent the number of valid integers in array.

int array[100] = {0};
int i = 0;

while (i < 100)
{
    int input;
    int scanresult = scanf("%d", &input);

    if (scanresult == 1)
    {
        // 1 item was successfully scanned
        array[i] = input;
        i++;
    }
    else
    {
        // either EOF was reached or the input was not scannable as an integer
    }
}

Upvotes: 0

chux
chux

Reputation: 154315

How can I fix my code so that I correctly read in the integers?

Use strtol() to parse the string as suggested by @EOF. It provides an end pointer where it left off.

long *array = malloc(sizeof *array * size);
if (array == NULL) Handle_OutOfMemory();

char *p = buf;
size_t i;
for(i = 0; i<size; i++) {
  // Cope with white space with nothing after it.
  while (isspace((unsigned char) *p)) p++;
  if (*p == '\0') break;

  char *end;
  errno = 0;
  long num = strtol(p, &end, 10);
  // If no conversion or out of range ...
  if (p == end || errno) {
    fprintf(stderr, "trouble converting `%s` into an integer.\n", p);
    break;
  }
  array[i] = num;
  p = end;
}

// Use array[0] ... array[i-1]

Upvotes: 1

v7d8dpo4
v7d8dpo4

Reputation: 1399

unsigned int len=0,tmp=0;
char j,isnumber=0;
for(char*i=buf;j=*i;i++)
{
    if(j>='0'&&j<='9')
    {
        tmp=tmp*10+j-'0';
        isnumber=1;
    }
    else
    {
        if(isnumber)
            array[len++]=tmp;
        tmp=0;
        isnumber=0;
    }
}

Also, you don't need

buf[strlen(buf) - 1] = '\0';

size = (strlen(buf)/2)+1;

Upvotes: 0

Related Questions