1

I have this database and I Need to check whether a Product Name is already in the database otherwise I ask the user to input another one.

The problem is this:

I'm trying to compare a string (the Product Name) found inside the struct with the string the user inputs.

The coding of the struct, the user input part and the search method are here below:

product Structure

typedef struct
{
    char    pName[100];
    char    pDescription [100];
    float   pPrice;
    int     pStock;
    int     pOrder;
}product;

the checkProduct method:

int checkProduct (char nameCheck[100])
{
    product temp;
    p.pName = nameCheck;

    rewind (pfp);
    while (fread(&temp,STRUCTSIZE,1,pfp)==1)
    {
        if (strcmp (temp.pName,p.pName))
        {
            return 1;
        }
    }
    return 0;
}

and the user input part [part of the code]:

char nameCheck[100];
gets (nameCheck);
checkProduct (nameCheck);
while (checkProduct == 1)
{
    printf ("Product Already Exists!\n Enter another!\n");
    while (getchar() !='\n')
    {
        continue;
    }
}
p.pName = nameCheck;

Now I am having the following errors (I Use ECLIPSE):

on the line while (checkProduct == 1) [found in the user input] is giving me: "comparison between pointer and integer - enabled by default" marked by a yellow warning triangle

p.pName = nameCheck; is marked as a red cross and stopping my compiling saying: "incompatible types when assigning to type 'char [100] from type 'char*' ^---- Is giving me trouble BOTH in the userinput AND when I'm comparing strings.

Any suggestions how I can fix it or maybe how I can deference it? I can't understand why in the struct the char pName is being marked as '*' whereas in the char[100] it's not.

Any brief explanation please?

Thank you in advance

EDIT: After emending the code with some of below: THIS Is the INPUT NAME OF PRODUCT section;

char *nameCheck;
        nameCheck = "";
        fgets(nameCheck,sizeof nameCheck, stdin);

        checkProduct (nameCheck);

        int value = checkProduct (nameCheck);
        while (value == 1)
        {
            printf ("Product Already Exists!\n Enter another!\n");
            while (getchar() !='\n')
            {

            }
        }
        strcpy (p.pName, nameCheck);

this is the new checkName method

int checkProduct (char *nameCheck)
{
    product temp;
    strcpy (p.pName, nameCheck);

    rewind (pfp);
    while (fread(&temp,STRUCTSIZE,1,pfp)==1)
    {
        if (strcmp (temp.pName,p.pName) == 0)
        {
            return 1;
        }
    }
    return 0;
}
DodoSombrero
  • 767
  • 3
  • 15
  • 29

2 Answers2

3
p.pName = nameCheck; 

is wrong as you try to assign address of one array to another. What you probably want is to copy it.

Use strcpy() instead.

strcpy(p.pName, nameCheck);

while (checkProduct == 1)

Since checkProduct is a function, the above condition will always be false as the address of function won't be equal to 1. You can store the return value in another integer like this:

int value = checkProduct(nameCheck);
while (value == 1)
/* rest of the code */

Or rather simply:

while ( checkProduct(nameCheck) == 1 ) {
...

Note - I've not checked entire code, there might be other bugs apart from this one. Btw, if you are new to programming, you can start with small examples from textbooks and then work towards slightly complex stuff.

P.P
  • 117,907
  • 20
  • 175
  • 238
Swapnil
  • 8,201
  • 4
  • 38
  • 57
  • the problem is how to pass the characters from the userinput (nameCheck) into that method. Then from then I'm creating a temporary struct and I want to assign the name from the Userinput INTO that temporary but how I don't know – DodoSombrero Dec 21 '12 at 19:12
  • @user1919739 You can use strcpy() or similar functions. See the edit now. – P.P Dec 21 '12 at 19:14
  • Yes i saw it, but still says the problem about how to declare the 'char' because the struct is considered as *char (although in the struct it is declared as an array of characters) and when I'm creating the new char[100], it's not letting me strcpy the char* with the char[] – DodoSombrero Dec 21 '12 at 19:17
  • user1919739 - I think's high time to you go back and start reading the basics of C programming. – Swapnil Dec 21 '12 at 19:20
0
int checkProduct (char nameCheck[100])

Note that the type signature is a lie. The signature should be

int checkProduct(char *nameCheck)

since the argument the function expects and receives is a pointer to a char, or, to document it for the user that the argument should be a pointer to the first element of a 0-terminated char array

int checkProduct(char nameCheck[])

Arrays are never passed as arguments to functions, as function arguments, and in most circumstances [the exceptions are when the array is the operand of sizeof, _Alignof or the address operator &] are converted to pointers to the first element.

    {
        product temp;
        p.pName = nameCheck;

Arrays are not assignable. The only time you can have an array name on the left of a = is initialisation at the point where the array is declared.

You probably want

strcpy(p.pName, nameCheck);

there.

        rewind (pfp);
        while (fread(&temp,STRUCTSIZE,1,pfp)==1)
        {
            if (strcmp (temp.pName,p.pName))

strcmp returns a negative value if the first argument is lexicographically smaller than the second, 0 if both arguments are equal, and a positive value if the first is lexicographically larger than the second.

You probably want

if (strcmp(temp.pName, p.pName) == 0)

there.

    gets (nameCheck);

Never use gets. It is extremely unsafe (and has been remoed from the language in the last standard, yay). Use

fgets(nameCheck, sizeof nameCheck, stdin);

but that stores the newline in the buffer if there is enough space, so you have to overwrite that with 0 if present.

If you are on a POSIX system and don't need to care about portability, you can use getline() to read in a line without storing the trailing newline.

    checkProduct (nameCheck);

You check whether the product is known, but throw away the result. Store it in a variable.

    while (checkProduct == 1)

checkProduct is a function. In almost all circumstances, a function designator is converted into a pointer, hence the warning about the comparison between a pointer and an integer. You meant to compare to the value of the call you should have stored above.

    {
        printf ("Product Already Exists!\n Enter another!\n");
        while (getchar() !='\n')

You read in characters without storing them. So you will never change the contents of nameCheck, and then be trapped in an infinite loop.

        {
            continue;
        }

If the only statement in a loop body is continue;, you should leave the body empty.

    }
    p.pName = nameCheck;

Once again, you can't assign to an array.


Concerning the edit,

char *nameCheck;
nameCheck = "";
fgets(nameCheck,sizeof nameCheck, stdin);

you have changed nameCheck from an array to a pointer. That means that sizeof nameCheck now doesn't give the number of chars you can store in the array, but the size of a pointer to char, which is independent of what it points to (usually 4 on 32-bit systems and 8 on 64-bit systems).

And you let that pointer point to a string literal "", which is the reason for the crash. Attempting to modify string literals is undefined behaviour, and more often than not leads to a crash, since string literals are usually stored in a read-only segment of the memory nowadays.

You should have left it at

char nameCheck[100];
fgets(nameCheck, sizeof nameCheck, stdin);

and then you can use sizeof nameCheck to tell fgets how many characters it may read, or, alternatively, you could have a pointer and malloc some memory,

#define NAME_LENGTH 100
char *nameCheck = malloc(NAME_LENGTH);
if (nameCheck == NULL) {
    // malloc failed, handle it if possible, or
    exit(EXIT_FAILURE);
}
fgets(nameCheck, NAME_LENGTH, stdin);

Either way, after getting input, remove the newline if there is one:

size_t len = strlen(nameCheck);
if (len > 0 && nameCheck[len-1] == '\n') {
    nameCheck[len-1] = 0;
}
// Does windows also add a '\r' when reading from stdin?
if (len > 1 && nameCheck[len-2] == '\r') {
    nameCheck[len-2] = 0;
}
Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
  • Thank you very much! I have understood it. since you said about the POSIX system and so, Our lecturer wants us to use ONLY MinGW (C89/C90) so I pretty guess all these work? so gets is mostly discarded? – DodoSombrero Dec 21 '12 at 19:27
  • I don't know if MinGW implements the POSIX standard(s), actually. I half expect it, because it's sort of a Unix compatibility layer for Windows, but I'm not sure. So the portable and safe way is `fgets`. Concerning `gets`, let me quote the man page: "Never use `gets()`. Because it is impossible to tell without knowing the data in advance how many characters `gets()` will read, and because `gets()` will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use `fgets()` instead." – Daniel Fischer Dec 21 '12 at 19:33
  • oh ok thanks, I don't know but now when I'm trying to run the program and enter the input it's literally crashing my cmd... – DodoSombrero Dec 21 '12 at 19:44
  • With what code? And what does "crashing" mean here? Segmentation fault? – Daniel Fischer Dec 21 '12 at 19:46
  • "CustomerOrders.exe has stopped worrking" I'm tyring to see which code but I think it's something with the inputs – DodoSombrero Dec 21 '12 at 20:07
  • I meant that I'd like to see the code you now use for input, can't diagnose anything without seeing that. – Daniel Fischer Dec 21 '12 at 20:10
  • Added explanation to the answer. In short, the crash is because you let `nameCheck` point to a string literal. Besides that, you didn't provide space for `fgets` to store the input. – Daniel Fischer Dec 21 '12 at 20:43
  • Thank you very much Daniel Fischer and all the others! It worked like a charm the char nameCheck[100], and the using fgets! Thank you so much. – DodoSombrero Dec 21 '12 at 21:01