0

As mentioned in the title, I don't know how to pass a char array to a struct array within a function.

The task is to write a little warehouse system, where you can add / remove / search for items. But in order to add / remove a Item, it should be checked whether the item already exists or not.

I have to use a struct and an array of this struct. My current approach is really buggy and I tried several hours to fix this but at this point I don't even know what to fix..

Important note: I am not allowed to use any other library than stdio.h and string.h and I am not allowed to use anything else than scanf for input and printf for output. I have to compare both strings with strcmp and I don't think that I am allowed to use strncpy.

Perhaps my whole approach is wrong..

Here is my code

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

#define LENGTHITEM 100
#define NUMBEROFITEMS 100

typedef struct WareHouse_ {
    char item[LENGTHITEM];
    int number;
} WareHouse;

void newItem(char*, WareHouse*, int);

int main() {

    int end = 0; int inputNumber = 0;
    char decision; char inputItem[NUMBEROFITEMS];
    WareHouse wHouse[NUMBEROFITEMS];

    printf("\nWelcome!");
    printf("\n\nYou can choose the following:");

    while (end != 1) {
        printf("\n\nNew Item (H) / Delete Item (E) | Search Item (S) | Table (A) | End (B): ");
        scanf("%c", &decision);

        switch(decision) {
            case 'h':
            case 'H': printf("\nName: ");
                      scanf("%s, inputItem);
                      printf("Number: "); 
                      scanf("%i", &inputNumber); <-- Here it says: scanf used to convert a string to an integer value (CLion)
                      newItem(inputItem, wHouse, inputNumber);
                      break;
            case 'e':
            case 'E': printf("\nTest E");
                      break;
            case 's':
            case 'S': printf("\nTest S");
                      break;
            case 'a':
            case 'A': printf("\nTest A");
                      break;
            case 'b':
            case 'B': printf("\nGood bye!");
                      end++;
                      break;
        }
    }
    return 0;
}

void newItem(char *inputItem, WareHouse *wHouse , int inputNumber) {

    for (int i = 0; i < NUMBEROFITEMS; i++) {
        if (strcmp(inputItem, wHouse[i].item) == 0) {
            printf("\nItem already exists, number increased %i", inputNumber);
            wHouse[i].number+= inputNumber;

        } else if (strcmp(inputItem, wHouse[i].item) < 0 || strcmp(inputItem, wHouse[i].item) > 0) {
            wHouse[i].number+= inputNumber;

            <-- Here I want to pass the "inputItem" into the "wHouse" array but I don't know how.. -->
        }
    }
}


Program:

    Welcome

    You can choose the following:

    New Item (H) / Delete Item (E) | Search Item (S) | Table (A) | End (B): H <-- My input

    Name and number (Name Number): fish 10 <-- My input


    New Item (H) / Delete Item (E) | Search Item (S) | Table (A) | End (B): <-- BUG IT APPEARS TWO TIMES

    New Item (H) / Delete Item (E) | Search Item (S) | Table (A) | End (B): H

    Name and number (Name Number): fish 10 <-- My input

    <-- Here it should output: "Item already exists, number increased 10" but it does nothing -->


    New Item (H) / Delete Item (E) | Search Item (S) | Table (A) | End (B): <-- BUG IT APPEARS TWO TIMES

    New Item (H) / Delete Item (E) | Search Item (S) | Table (A) | End (B): B

    Good bye

Andrew
  • 4,264
  • 1
  • 21
  • 65
  • You’re else clause does not make sense, does it? How do you ensure you don’t overwrite an existing item if strcmp does not match? Also, why not reading strings and amount separately? It’s more often recommended to use fgets for reading strings. Also, what does fflush do? – j3141592653589793238 Dec 07 '19 at 11:55
  • 1
    Fyi, whatever book, website, tutorial, or acquaintance informed you `fflush(stdin);` is the standard method for clearing the `stdin` stream, they were wrong. [See here](https://stackoverflow.com/questions/2979209/using-fflushstdin). – WhozCraig Dec 07 '19 at 11:57
  • @user0800 As mentioned before, I am not allowed to use fgets.. And my else should say "If item doesn't exists". – Andrew Dec 07 '19 at 12:04
  • @WhozCraig My professor did. – Andrew Dec 07 '19 at 12:05
  • Right, I missed that one. How do you prevent overwriting though? – j3141592653589793238 Dec 07 '19 at 12:05
  • @user0800 I thought that ```if (strcmp(inputItem, wHouse[i].item) == 0)``` would prevent that, because it only adds an amount of item numbers at the index i, if the string comparison is true. And as mentioned before, I don't know how to pass the ```inputItem``` inside the ```wHouse``` array – Andrew Dec 07 '19 at 12:08
  • @Andrew Then you definitely need to read [that link](https://stackoverflow.com/questions/2979209/using-fflushstdin). Your professor is flat-wrong. If they grief you about it, kindly refer them to the language standard. It's covered in Section 7.21.5.2 The `fflush` function. – WhozCraig Dec 07 '19 at 12:23
  • @WhozCraig I already deleted the fflush thing. But it changed nothing. Still dont know how to pass the ```inputItem``` inside the ```wHouse``` array... – Andrew Dec 07 '19 at 12:26
  • `scanf(%i", inputNumber);` should be `scanf("%i", &inputNumber);`. (add `"` and `&`) – MikeCAT Dec 07 '19 at 12:36
  • @Andrew Do you think you are allowed to use `strcpy`? How about `memcpy` and `strlen`? – MikeCAT Dec 07 '19 at 12:38
  • @MikeCAT Thanks, I wrote that wrong above but It was correct in my code. No, I don't think that I am allowed to use strcpy, memcpy and strlen (as mentioned above). But here is my thought: What if i dont write an extra function which adds / removes Items from my array ```wHouse``` and instead of that, I write everything in my main class (without any function)? Could this solve my problem or is there no way to solve my problem without using strcpy? – Andrew Dec 07 '19 at 12:42

1 Answers1

1

To put a string into another array without strncpy(), you can use strcpy().

strcpy(wHouse[i].item, inputItem);

Another way is to calculate length to copy via strlen() and copying via memcpy().

size_t len = strlen(inputItem);
memcpy(wHouse[i].item, inputItem, len + 1); /* +1 for terminating null character */

If both of these ways are not allowed, you can copy each characters by yourself.

for (size_t p = 0; ; p++) {
    wHouse[i].item[p] = inputItem[p];
    /* break here (not via loop condition) instead of loop condition for copying terminating null character */
    if (inputItem[p] == '\0') break;
}

And I found three other problems in your code.

Firstly, the array wHouse is used without initializing, so you are using indeterminate values for calculation and invoking undefined behavior.

Initlalization can be done like this:

WareHouse wHouse[NUMBEROFITEMS] = {{"", 0}};

You can specify the value for only first element, and the left elements will be automatically initialized to "zero".

Secondly, the choice is displayed twice because newline characters are read via %c. To avoid this, you can add a space characte before %c to tell scanf ignore whitespace characters.

scanf(" %c", &decision);

Thiredly, if you add the "passing" in the newItem() function like you say, all elements will be modified because elements are modified for all values that strcmp() returns. Instead, I guess you want to modify the first empty element when specified item is not found.

To realize this, you can write like this:

void newItem(char *inputItem, WareHouse *wHouse , int inputNumber) {

    int itemFound = 0; /* set to 1 when specified item is found */
    int firstEmptyItem = -1; /* set to the index of the first empty item */

    for (int i = 0; i < NUMBEROFITEMS; i++) {
        if (strcmp(inputItem, wHouse[i].item) == 0) {
            printf("\nItem already exists, number increased %i", inputNumber);
            wHouse[i].number+= inputNumber;

            itemFound = 1; /* the item is found! */

        } else if (strcmp("", wHouse[i].item) == 0) { /* check if this item is empty */
            /* if empty and index is not written yet, write the index */
            if (firstEmptyItem < 0) firstEmptyItem = i;

        }
    }
    /* if the item is not found, and a room to add new item exists */
    if (!itemFound && firstEmptyItem >= 0) {
        int i = firstEmptyItem; /* set index (or you can use firstEmptyItem directly in the following code) */

        wHouse[i].number+= inputNumber;

        /* Here you should pass the "inputItem" into the "wHouse" array. */
    }
}
MikeCAT
  • 73,922
  • 11
  • 45
  • 70
  • What do you mean with "item i = firstEmptyItem;". I only get an error there. – Andrew Dec 07 '19 at 13:29
  • @Andrew Sorry, it is my mistake and `item` should be `int`. – MikeCAT Dec 07 '19 at 13:31
  • It works. I love you. At this moment, I don't exactly know what it does but I think thats a small problem that I will solve. Now I have to do the same thing with deleting an item :D – Andrew Dec 07 '19 at 13:42
  • what does the "size_t" mean? – Andrew Dec 07 '19 at 19:27
  • `size_t` is an unsigned integer type for storing object size. – MikeCAT Dec 07 '19 at 23:34
  • What if I don't want to use ```size_t``` ? Is ther another way to solve this without ```size_t``` ? – Andrew Dec 07 '19 at 23:41
  • Yes, you can do like this: `for (char *dst = wHouse[i].item, *src = inputItem; (*dst = *src) != '\0'; dst++, src++);` – MikeCAT Dec 07 '19 at 23:45
  • What does ```if(strcmp("", wHouse[i].item) == 0)``` mean? Why cant I say ```if(strcmp(inputItem, wHouse[i].item) != 0)``` ? – Andrew Dec 09 '19 at 11:52
  • It is checking if the element is empty. If you use `if(strcmp(inputItem, wHouse[i].item) != 0)`, you will destroy an existing item. – MikeCAT Dec 13 '19 at 13:12