SarcasticLeo
SarcasticLeo

Reputation: 56

Can't figure out how to extract multiple doubles from a string and store them in a array of double

I'm still new to C (and programming in general) so I'm trying to practice some of C concepts before some upcoming assignment.

I'm trying to write a simple program that takes all input from the keyboard but only stores doubles.

I also want my program to end if I type 'END' or if it reaches EOF (in case I feel like implementing file inputs in the future).

I'm trying to become more familiar with dynamic arrays so I chose to store all keyboard input in a dynamic string first and then the plan is to extract doubles from said string and store them in a dynamic array of doubles.

My current issue is that I can't figure out how to isolate each double within the string while ignoring the other characters. So far, I've tried using scanf(), sscanf() and strtod(). I've read the official documentation but with my limited understanding I can't get them to do what I want.

My plan was to use a blank space as a delimiter to separate each double value. Unfortunately, I can't figure out how to "move forward" within the string and thus each index of my double array ends up getting filled up with the same double value, which is always the first one in the String.

I left some of my previous failed attempts in the code below for better context:

#define _CRT_SECURE_NO_WARNINGS

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

//Function handles the logic for figuring out if 'END' was typed in.
bool ifEnd(char* userString, size_t counter) {
    bool userEnd = false;

    for (size_t index = 0; index < counter; index++)
    {
        if ((userString[index - 2] == 'E' && userString[index - 1] == 'N' && userString[index] == 'D')) {
            userEnd = true;
        }
        else if ((userString[index - 3] == 'Q' && userString[index - 2] == 'U' && userString[index - 1] == 'I' && userString[index] == 'T')) {
            userEnd = true;
        }
    }
    return userEnd;
}

int main()
{   size_t size = 10;
    size_t latestIndex = 0;
    char* string = malloc(size*sizeof(char));
    char* dummyP = string;

    string[0] = toupper(getchar());
    for (size_t index = 0; (string[index] != EOF) && (ifEnd(string, index) == false);) {
        //Replacing newline characters with a blank space
        if (string[index] == '\n')
            string[index] = ' ';

        if (index == (size - 2))
        {
            if ((dummyP = realloc(string, (size *= 2) * sizeof(char))) == NULL)
            {
                printf("No memory available, see ya!");
                return EXIT_FAILURE;
            }
            else {
                string = dummyP;
                dummyP = NULL;
            }
        }
        ++latestIndex;
        ++index;
        string[index] = toupper(getchar());
    }

    //Getting rid of EOF and placing a '\0' at the end of the String.
    if(string[latestIndex] == EOF)
        string[latestIndex] = '\0';
    else
        string[latestIndex+1] = '\0';

    double* p = NULL;
    size = 10;
    double* doubleArray = malloc(size * sizeof(double));

    for (size_t index = 0; string[index] != '\0'; index++) { 
        
        if (index == (size - 2))
        {
            if ((dummyP = realloc(doubleArray, (size *= 2)*sizeof(double))) == NULL)
            {
                printf("No memory available, see ya!");
                return EXIT_FAILURE;
            }
            else {
                doubleArray = dummyP;
                dummyP = NULL;
            }
        }

        //In one of my failed attempts (see my commented out code below), I tried following 
        //an example I found in `strtod`'s documentation where you can "juggle" two pointers 
        //to keep track of your place in the string. It started giving me memory violation 
        // and breaking point issues

        /*if (index % 2 == 0) {
            doubleArray[index] = strtod(string, &p);
            printf("\n%lf --i- ", doubleArray[index]);
        }
        else if (index % 2 == 1) {
            doubleArray[index] = strtod(p, &string);
            printf("\n%lf --p- ", doubleArray[index]);
        }
        else
            printf("\n||||This shouldn't happen||||\n");
        printf("%lf", *p);*/


//More failed attempts (strings below have a limit for ease of 
 //coding but I would've changed them to be dynamic if the method 
//below had work)
         /* char temp [100] = {'0'};
       sscanf(string, "%s", &temp);
       //doubleArray[index] = strtod(temp, NULL);
        printf("\n%lf --- ", doubleArray[index]);*/

       /* double temp [100] = {'0'};
       sscanf(string, "%lf", &doubleArray[index]);/*
       
       /*doubleArray[index] = strtod(temp, NULL);
        printf("\n%lf --- ", doubleArray[index]);*/

     /*doubleArray[index] = strtod(sscanf(string, %s, temp),NULL);*/

    doubleArray[index] = strtod(string, NULL);
    printf("\n%lf --- ", doubleArray[index]);

    }
    //printf("%s", string);

    free(string);
    //free(p);
    free(doubleArray);
}

Any help, suggestions or advice would be really appreciated.

Upvotes: 0

Views: 90

Answers (1)

chux
chux

Reputation: 154272

to extract multiple doubles from a string and store them in a array of double

  1. Parse the string to find the number of double. Use strtod().

  2. Form the array.

  3. Parse the string again and save the values.


Use the end pointer from strtod() know when to begin parsing for the next double.

// Return count of successfully parsed double.
// Return -1 if non-double detected
int string_to_doubles(double *d, const char *src) {
  int count = 0;
  while (*src) {
    char *endptr;
    double x = strtod(src, &endptr);
    if (src == endptr) {
      return -1;  // Non-numeric text.
    }
    src = (const char *) endptr; 
    count++;
    if (d) {
      *d++ = x;  // Saved parsed value
    }
    // Consume trailing white-space.
    while (isspace(*(unsigned char *)src)) {
      src++;
    }
  }
  return count;
}
     

Usage

int SL_parse(const char *s) {
  int count = string_to_doubles(NULL, s);
  if (count <= 0) {
    return count;
  }
  
  // to use an "array"
  double array_of_double[count];
  string_to_doubles(array_of_double, s);
  // ....
  
  // to use dynamic memory
  double *pointer_to_doubles = malloc(sizeof pointer_to_doubles[0] * count);
  if (pointer_to_doubles) {
    string_to_doubles(pointer_to_doubles, s);
    // ....
    free(pointer_to_doubles);
  }

  return count;
}

Upvotes: 2

Related Questions