1

Let me start off by saying, I do realize there are a lot of questions with the exact same title, but I didn't find what I was looking for in any of them. I tried to write the following code, in order to errorcheck the user's input, so he wouldn't give 2 variables the same name. Needless to say, it failed, and that is why I am here. While printing the strings I was comparing out as strings, using printf("%s", temp[j].name); was working fine, the character-by-character printing was outputting a series of characters that, from what I know, shouldn't be there. I would like to know what this could all be about, and if there is anyway to solve it, so I can actually compare the 2, without using something from string.h

Here is the code:

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

#define ARRAYLENGTH 20

typedef struct{
    char name[ARRAYLENGTH];
    char type[ARRAYLENGTH];
    char value[ARRAYLENGTH];
}variable;


int main(){
    int amount = 3;
    int i, j, k;
    variable * varray;
    variable * temp;
    int flag;
    int added = 1;

    varray = malloc(amount*sizeof(variable));
    if (varray == NULL){
        printf("error");
        return 1;
    }
        temp = malloc(amount*sizeof(variable));
    if (temp == NULL){
        printf("error");
        return 1;
    }
    printf("Give the name of variable # 1 \n");
    scanf("%s", varray[0].name);

    for (i = 1; i < amount; i++){
        flag = 0;
        while (flag == 0){
            printf("Give the name of variable # %d \n", i + 1);
            scanf("%s", temp[i].name);

            for (j = 0; j < added; j++){
                for (k = 0; temp[i].name[k] != '\0'; k++){
                    printf("%c,", temp[i].name[k]);
                }
                printf("\n");
                for (k = 0; temp[i].name[k] != '\0'; k++){
                    if (varray[j].name[k] != temp[i].name[k]){
                        flag = 1;
                        break;
                    }
                    if (varray[j].name[k] == temp[i].name[k]){
                        flag = 0;
                    }
                }
            }
            if (flag == 0){
                printf("The variable name you gave already exists, please choose another one. \n");
            }
            if (flag == 1){
                for (j = 0; j < ARRAYLENGTH; j++){
                    varray[i].name[j] = temp[i].name[j];
                }
            }
            if(flag == 1){
                added +=1;
            }
        }
    }
    for (i = 0; i < amount; i++){
        printf("%s \n", varray[i].name);
    }
    free(varray);
    free(temp);
}

The code compiles without problem, but when I tried to run it, I found that, no matter what my, as a user, input was, the flag would always be 1 in the end. The block of code

printf("\n");
for (k = 0; k < ARRAYLENGTH; k++){
    printf("%c,", temp[i].name[k]);
}
printf("\n");

And when the user input is the name John, outputs the following on Visual Studio 2013's Developer command prompt:

Give the name of variable # 1                                                                                                                         
John                                                                                                                                                  
Give the name of variable # 2                                                                                                                         
John                                                                                                                                                  
J,o,h,n,                                                                                                                                              
The variable name you gave already exists, please choose another one.                                                                                 
Give the name of variable # 2                                                                                                                         
George                                                                                                                                                
G,e,o,r,g,e,                                                                                                                                          
Give the name of variable # 3 
George                                                                                                                                                
G,e,o,r,g,e,                                                                                                                                          
G,e,o,r,g,e,                                                                                                                                          
The variable name you gave already exists, please choose another one.                                                                                 
Give the name of variable # 3                                                                                                                         
John                                                                                                                                                  
J,o,h,n,                                                                                                                                              
J,o,h,n,                                                                                                                                              
John                                                                                                                                                  
George                                                                                                                                                
John                 

What I am guessing this problem is about, is that the memory the system is allocating to temp and varray are already being used elsewhere. This errorcheck is crucial for a project I have to do, so I would appreciate any help I can get in solving this problem greatly. Thanks in advance,

LukeSykpe

Luke Sykpe
  • 311
  • 1
  • 11
  • 1
    The problem is that you're printing past the end of the word. You're always printing `ARRAYLENGTH` characters, even if the word is only 4 characters long. You need to stop when you get to the null character. – Barmar May 01 '15 at 23:57
  • @Barmar is correct. Try `for (k = 0; k < ARRAYLENGTH && temp[i].name[k] != '\0'; k++)` – bentank May 01 '15 at 23:59

2 Answers2

2

The problem is with your printing logic.

The scanf function writes the user input into the array, followed by a terminating `\0' character. It does not know the size of your array (20), so it doesn't touch the part of the array that it doesn't actually write.

Instead of this:

for (k = 0; k < ARRAYLENGTH; k++){

write:

for (k = 0; temp[i].name[k] != '\0'; k++) {

Note that you don't need to check for running off the end of the array here. Instead, make sure that the user string is not too big for your array. See this for how to do that.

Community
  • 1
  • 1
Craig S. Anderson
  • 6,966
  • 4
  • 33
  • 46
  • @LukeSykpe +1 to this answer as it is what i would have written. It is indeed due to the fact that you always read the 20 characters even if the user entered only 1 char. (At least for the printing misshap.) – Khaldor May 02 '15 at 00:21
  • I updated the code and command prompt output. It looks much better than before (The variable is indeed "J,o,h,n,"). The problem is, though that does solve what I thought was the cause of my condition not working (The one checking if `temp` and `varray` have the same value for `name`), without making the conditional itself working. It still prints the 3 "Johns" at the end, without calling for an error. The boolean flag is not becoming 0 for the while loop to...well, loop. It keeps ending up as 1, breaking the while loop. I can't seem to pinpoint the logical mistake in it. – Luke Sykpe May 02 '15 at 00:32
0

Edit : This post is not to answer the original question, but to answer a follow-up question posted in comments. I tried to incorporate this into the previous answer, but the owner refused. So here it is.

The problem with your varray comparisons is that, with the code you are showing at least, varray is never initialized. So

if (varray[j].name[k] != temp[i].name[k])

Is a bit like taking a random byte in memory, assigning it to a variable and doing this :

if (RandomByteValue != temp[i].name[k])

Which 90% of the time will be true thus setting your flag to 1. Essentially, you're missing a

varray[i] = lastVariableGotFromUser

At the end of each main loop.

--- Edit : Added in minor corrections to general functionality ---

Try adding in this :

int added = 1;

Then change this :

for (j = 0; j < amount; j++){

with :

for (j = 0; j < added; j++){

and add in :

        if (flag == 1){
            // Your for loop
            added += 1;
        }

What was happening was that you iterated through fields of varray that were uninitialized, and contained random memory. With those modifications (If i didn't forget one, it should work. Try to always limit your loops to only the useful iterations. If you know you only have one variable added in, don't iterate through the 3 fields.

------- Last edit to correct a detail in his code -------

So, your whole :

for (k = 0; temp[i].name[k] != '\0'; k++){

Can be deleted. Now i also know that you don't want to use string.h, However, recoding a strcmp ain't all that complicated. Let's call it

int comp_str(str, str2) // Returns 1 if they don't match, zero if they do.

then just replace your whole for with :

if (comp_str(temp[i].name, varray[j].name) == 0) {
    flag = 0;
    break;
}
else
    flag = 1;

You only want to set the flag when a whole string has been analyzed. So pass it to another function, act upon the return value, and it works! Generally slice your code up. Easier to act/think on. (and also avoids having things like varray[j].name[k] != temp[i].name[k] which is long an not so pleasing to read, in your code.)

Khaldor
  • 294
  • 1
  • 16
  • But I do have one. if (flag == 1){ varray[i].name[j] = temp[i].name[j]}, which should be the name the user gave earlier. At first, varray will not be initialized, the first loop around, the flag will be 1, and varray[0].name should be "John". If that is the case, the next time the loop runs, for i = 1, "John" should already exist in at least one spot in varray[] (varray[0].name), so it should give me an error message. Isn't that correct? And if not, why? – Luke Sykpe May 02 '15 at 01:53
  • So, I discovered why it doesn't work, I think. The first time I call `scanf` to read `temp[j].name` 's value as "John", it, for some reason saves a dash in it. I discovered that by calling a `printf` right after said `scanf`, which outputs - to the command prompt. Any idea why that might be? Also, I gave your answer some thought, and changed it so it starts from i=1, and the first value, for i=0 is simply read before entering the loop. The flag check still doesn't work for the 3rd loop-around, despite the value that time is John, and not -. I have updated the code. – Luke Sykpe May 03 '15 at 15:37
  • @LukeSykpe I would change a few things, i'll add them into my answer. Just wait until i get it put together. :-) – Khaldor May 04 '15 at 16:42
  • Thank you for your answer. I assumed by "//your for loop" you meant `for(j = 0; j < added; j++)`, so I made those modifications. Now, when I execute the code, it's stuck in a loop indefinetely, asking me to give name # 2, regardless of what the name is. (e.g., for the first name I have John, as in the prior example. Then, I gave "George", and it simply gave me the output of "Give name of variable # 2" again.) Furthermore, the error message ("Name already exists etc") was not displayed. – Luke Sykpe May 04 '15 at 20:48
  • So, in an attempt to correct that, I put the conditional you proposed alone, right before the end of my `while` loop. When I executed that piece of code, giving as name #1 John, and as name #2 trying John again, it worked, the error name was displayed correctly, and it asked me for a new #2, no matter how many times I said "John". When I finally choose George, it normally moves on to name #3. On name 3, whenever I give George, aka the name I gave on 2, it works just fine, error message and all, but when I say John, or the name I gave as name 1, in general, it saves it normally. Updating code. – Luke Sykpe May 04 '15 at 20:53
  • @LukeSykpe Adding in a last edit that should correct all. Indeed, i hadn't tested that case and forget it. :-) It's the loop that you use to compare that is problematic. – Khaldor May 04 '15 at 21:10
  • Thank you once more for your answer. I am not sure if I can use strcmp. The piece of code will be used in an assignment, which was given to us before we were introduced to string.h. I will ask my professor tomorrow, and, if not, I'll take a shot at recoding strcmp. – Luke Sykpe May 04 '15 at 22:26
  • I asked my professor, and he replied that after seval complaints by students, he decided to "lift the ban" on string.h, so I did use strcmp instead of recoding it. That said, the code you suggested works perfectly. Thanks a lot for your help. – Luke Sykpe May 06 '15 at 19:54
  • @LukeSykpe Meh. I'd have said go re-code it. It's a loop. But hey, glad to hear it works. :-) Good luck on your future endeavors. – Khaldor May 06 '15 at 19:58