An Array of Arrays

Viewed 83

I want to store a group of arrays containing 2 numbers in an array. But I only want 2 numbers to be stored when 5 followed by a comma and another number is entered. Essentially, what I want my program to do is read from this array of arrays and perform tasks accordingly. So if the user enters 2, I want to store (2,0) in one space of my array and move on to ask my user for the second number. But if the user types 5,10 I want the program to store (5,10) in that same array. Then my program could filter which array has only one value and which has 2 and do different tasks accordingly. My assignment requires us to not ask 2 numbers for each array which would have made it easier.

This is what I have so far and I know I'm wrong I just don't know where to go from here:

    int main(void)
{
    int size = 0;
    int input;
    int factor;
    int mdArrays[100][2];
    
    for (size_t i = 0; i < 100; i++)
    {
        size = i;
        scanf("%d,%d", &input, &factor);
        
        if (input != 5 && input != 9)
        {
            factor = 0;
            for (size_t j =0 ; j< 2; j++)
            {
                mdArrays[i] = input;
                mdArrays[j] = factor;
            }
                
            
        }
        else if (input == 9)
        {
            break;
        }
        else 
        {
            for(int j = 0; j< 2; j++)
            {
                mdArrays[i] = input;
                mdArrays[j] = factor;
            }
        }
        
        
    }
    
    for (size_t i =0; i < size; i++)
    {
        for(size_t j = 0; j < 2; j++)
        {
            printf("%d,%d", mdArrays[i[j]]);
        }
    }
}
2 Answers

There were a few issues.

size is one too short (it should be i + 1).

It may be possible to handle 5 vs 5,23 using scanf. But, I prefer to use fgets and strtol and check the delimiter (e.g. whether it's , or not).

The if/else ladder logic can be simplified if we make the first test against input == 9 to stop the loop.

According to your code, you want to force a factor of zero if input != 5. That doesn't make much sense to me, but I've kept that logic [for now].

That may not be what you want/need, but it was my best interpretation of your code. The main purpose is to differentiate how many numbers are on a given line. So, adjust the rest as needed.

I think the way you're storing/displaying the array is incorrect. I believe you want to store input into mdArrays[i][0] and factor into mdArrays[i][1]. Using j makes no sense to me.

As I mentioned [in my top comments], the printf in the final loop is invalid.

Note that the code is cleaner if we don't hardwire the dimensions with a literal 100 in multiple places (e.g. once in the myArrays declaration and again in the outer for loop). Better to use (e.g.) #define MAXCOUNT 100 and replace 100 elsewhere with MAXCOUNT (see below).

I created three versions. One that is annotated with original and fixed code. Another that removes the original code. And, a third that organizes the data using a struct.


Here's the refactored code. I've bracketed your/old code [vs. my/new code] with:

#if 0
// old code
#else
// new code
#endif

I added a debug printf. Anyway, here's the code with some annotations:

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

int
main(void)
{
    int size = 0;
    int input;
    int factor;
    int mdArrays[100][2];

    for (size_t i = 0;  i < 100;  i++) {
#if 0
        size = i;
        scanf("%d,%d",&input,&factor);
#else
        // get line
        char buf[100];
        char *cp = fgets(buf,sizeof(buf),stdin);
        if (cp == NULL)
            break;

        // strip newline -- only needed for debug print
        cp = strchr(buf,'\n');
        if (cp != NULL)
            *cp = 0;

        // decode first number
        input = strtol(buf,&cp,10);

        // decode second number if it exists -- otherwise, use a sentinel
        if (*cp == ',')
            factor = strtol(cp + 1,&cp,10);
        else
            factor = -1;

        printf("DEBUG: buf='%s' input=%d factor=%d\n",buf,input,factor);
#endif

        // stop input if we see the end marker
        if (input == 9)
            break;

        // remember number of array elements
        size = i + 1;

        // only use a non-zero factor if input is _not_ 5
        if (input != 5) {
            factor = 0;
#if 0
            for (size_t j = 0;  j < 2;  j++) {
                mdArrays[i] = input;
                mdArrays[j] = factor;
            }
            continue;
#endif
        }

#if 0
        for (int j = 0;  j < 2;  j++) {
            mdArrays[i] = input;
            mdArrays[j] = factor;
        }
#else
        mdArrays[i][0] = input;
        mdArrays[i][1] = factor;
#endif
    }

    for (size_t i = 0;  i < size;  i++) {
#if 0
        for (size_t j = 0;  j < 2;  j++) {
            printf("%d,%d",mdArrays[i[j]]);
        }
#else
        printf("%d,%d\n",mdArrays[i][0],mdArrays[i][1]);
#endif
    }

    return 0;
}

Here's the sample input I used to test:

5,3
7,6
8,9
5,37
5
9,23

Here's the program output:

DEBUG: buf='5,3' input=5 factor=3
DEBUG: buf='7,6' input=7 factor=6
DEBUG: buf='8,9' input=8 factor=9
DEBUG: buf='5,37' input=5 factor=37
DEBUG: buf='5' input=5 factor=-1
DEBUG: buf='9,23' input=9 factor=23
5,3
7,0
8,0
5,37
5,-1

Here's a slightly cleaned up version:

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

#define MAXCOUNT    100

int
main(void)
{
    int size = 0;
    int input;
    int factor;
    int mdArrays[MAXCOUNT][2];

    for (size_t i = 0;  i < MAXCOUNT;  i++) {
        // get line
        char buf[100];
        char *cp = fgets(buf,sizeof(buf),stdin);
        if (cp == NULL)
            break;

        // strip newline -- only needed for debug print
#ifdef DEBUG
        cp = strchr(buf,'\n');
        if (cp != NULL)
            *cp = 0;
#endif

        // decode first number
        input = strtol(buf,&cp,10);

        // decode second number if it exists -- otherwise, use a sentinel
        if (*cp == ',')
            factor = strtol(cp + 1,&cp,10);
        else
            factor = -1;

#ifdef DEBUG
        printf("DEBUG: buf='%s' input=%d factor=%d\n",buf,input,factor);
#endif

        // stop input if we see the end marker
        if (input == 9)
            break;

        // remember number of array elements
        size = i + 1;

        // only use a non-zero factor if input is _not_ 5
        if (input != 5)
            factor = 0;

        mdArrays[i][0] = input;
        mdArrays[i][1] = factor;
    }

    for (size_t i = 0;  i < size;  i++)
        printf("%d,%d\n",mdArrays[i][0],mdArrays[i][1]);

    return 0;
}

You might benefit from using a struct [YMMV], so here's a version that keeps things organized that way:

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

#define MAXCOUNT    100

typedef struct {
    int input;
    int factor;
} data_t;

int
main(void)
{
    int size = 0;
    data_t mdArrays[MAXCOUNT];
    data_t *data;

    for (size_t i = 0;  i < MAXCOUNT;  i++) {
        // get line
        char buf[100];
        char *cp = fgets(buf,sizeof(buf),stdin);
        if (cp == NULL)
            break;

        // strip newline -- only needed for debug print
#ifdef DEBUG
        cp = strchr(buf,'\n');
        if (cp != NULL)
            *cp = 0;
#endif

        data = &mdArrays[i];

        // decode first number
        data->input = strtol(buf,&cp,10);

        // decode second number if it exists -- otherwise, use a sentinel
        if (*cp == ',')
            data->factor = strtol(cp + 1,&cp,10);
        else
            data->factor = -1;

#ifdef DEBUG
        printf("DEBUG: buf='%s' input=%d factor=%d\n",buf,input,factor);
#endif

        // stop input if we see the end marker
        if (data->input == 9)
            break;

        // remember number of array elements
        size = i + 1;

        // only use a non-zero factor if input is _not_ 5
        if (data->input != 5)
            data->factor = 0;
    }

    for (size_t i = 0;  i < size;  i++) {
        data = &mdArrays[i];
        printf("%d,%d\n",data->input,data->factor);
    }

    return 0;
}

Read a line of user input with fgets() and then parse it to see if it is one number, two comma separated numbers or something else.

I recommend using `"%n" to detect when and how scanning finished.

int get_numbers(int *input, int *factor) {
  char buf[80];
  if (fgets(buf, sizeof buf, stdin)) {
    int n = 0;
    sscanf(buf, "%d %n", input, &n);
    if (n > 0 && buf[n] == '\0') return 1;
    n = 0; 
    sscanf(buf, "%d ,%d %n", input, factor, &n);
    if (n > 0 && buf[n] == '\0') return 2;
    return 0; // Invalid input
  }
  return EOF;  // No input
}

Usage

// scanf("%d,%d", &input, &factor);
switch (get_numbers(&input, &factor)) {
  case 2: printf("%d %d\n", input, factor); break;
  case 1: printf("%d\n", input); break;
  case 0: printf("Invalid input\n"); break;
  case EOF: printf("No input\n"); break;
}
Related