1

I am trying to make all the names in the Struct lowercase so that I can compare them and remove them.

int removeNameCard(NameCard *idCard, int *size){
    char name[80];
    char *ptr;
    char rubbish;
    int a = 0, c = 0;
    printf("removeNameCard():\n");
    printf("Enter personName:\n");
    scanf("%c", &rubbish); // Why is there a '\n' char here??
    fgets(name, 80, stdin);
    if((ptr = strchr(name, '\n'))){
        *ptr = '\0';
    }
    if((*size) == 0){
        printf("The name card holder is empty\n");
        return 0;
    }
    // Convert everything to Lower Case first
    while(name[a]){
        name[a] = tolower(name[a]);
        a += 1;
    }
    printf("tolower(): %s", name);
    for(int b = 0; b < *size; b += 1){
        // Why is this Dot Notation when I passed in a pointer to the Struct?
        while (idCard[b].personName)[c]){
            (idCard[b].personName)[c] = tolower((idCard[b].personName)[c]);
            c += 1;
        }
    }
    for(int i = 0; i < *size; i += 1){
        if((idCard[i].personName) == name){
                                    printf("%d. This is from Holder: %s, This is from User: %s", i,(idCard[i].personName),name);
            printf("The name card is removed\n");
            printf("nameCardID: %d\n", idCard[i].nameCardID);
            printf("personName: %s\n", idCard[i].personName);
            printf("companyName: %s\n", idCard[i].companyName);
            int k = 0;
            do{
                idCard[i+k].nameCardID = idCard[i+k+1].nameCardID;
                strcpy((idCard[i+k].personName),(idCard[i+k+1].personName));
                strcpy((idCard[i+k].companyName),(idCard[i+k+1].companyName));
            }while((i+k+1) != (*size + 1));
        }
    }
    return 0;
}

However, I am rather confused why the Compiler asked me to use Dot Notation instead of Pointer Notation as I thought I passed in the address of the Struct into *idCard so it should be a pointer if I am not wrong?

And am I wrong for trying to access each individual character in every name of the Struct like this?: (idCard[b].personName)[c]

Thank you

  • 1
    I can't help to think that your [mre] could be even more minimal. – Some programmer dude Nov 05 '21 at 08:18
  • If `idCard` is an array of `NameCard` structures, then `idCard[b]` is such an `NameCard` structure *object*. `idCard[b]` is not a pointer to a structure (where the "arrow" operator `->` would be used). That's why the "dot" operator`.` should be used in `idCard[b].personName`. – Some programmer dude Nov 05 '21 at 08:20
  • Also you don't need parentheses for `(idCard[b].personName)[c]`, `idCard[b].personName[c]` works just as well. – Some programmer dude Nov 05 '21 at 08:22
  • 1
    BTW: `if((idCard[i].personName) == name){` is not the way to compare strings, – wildplasser Nov 05 '21 at 09:20
  • 1
    @Antoine Yes, it has helped me greatly in understanding the reasons for both operators to exist, although I would probably have to code more to fully appreciate what the comment has explained in full. Thank you so much, I have learnt a lot :> – Michelin_Boi Nov 06 '21 at 07:25
  • @Someprogrammerdude I am sorry for my poor post. Thank you for sharing wif me the guidelines on how I can post better, I will check it out!! – Michelin_Boi Nov 06 '21 at 07:25
  • @Someprogrammerdude I see!! I have mistakenly thought that ```idCard[b]``` to be a pointer. However, I was wondering when I pass ```idCard[b]``` into a helper function that takes a pointer to a struct, does it automatically reduce ```idCard[b]``` to a pointer as I seem to recall reading about it being the case like this – Michelin_Boi Nov 06 '21 at 07:28
  • @wildplasser thank you!! I have a bad habit of doing that when I am supposed to be using strcmp(). – Michelin_Boi Nov 06 '21 at 07:29

2 Answers2

2

However, I am rather confused why the Compiler asked me to use Dot Notation instead of Pointer Notation…

idCard[i] is a structure, not a pointer to a structure, so its members are accessed as idCard[i].member, not idCard[i]->member.

idCard[i] is a structure because whenever x is a pointer, x[i] is one of the objects that x points to. It is not the address of the object. You could calculate the address of the object with x+i, and then you could reference the object with *(x+i). And x[i] is actually defined in this way; x[i] is defined to be *(x+i). (In case of expressions generally, E1[E2] is defined to be (*((E1)+(E2))).)

And am I wrong for trying to access each individual character in every name of the Struct like this?: (idCard[b].personName)[c]

This will work, but the parentheses are unnecessary. You can use idCard[b].personName[c]. Due to the C grammar, it is already grouped as (idCard[b].personName)[c].

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Thank you so much for the clarifications. However, I am still a bit confused. Do you mean that if ```x``` is a pointer to a Struct, it would have the same members as the Struct, which is why it can point to various objects using ```x[i]```? – Michelin_Boi Nov 06 '21 at 07:35
  • Apologies but why will ```x+i``` give me the address of the object? I was under the impression that pointers will point to the first member of a Struct if I did not specify which member/object to specifically point to? Thank you very much – Michelin_Boi Nov 06 '21 at 07:36
  • 1
    @Michelin_Boi: If `x` is a pointer to a structure, it does not have any members. A pointer just points to a place in memory; it does not contain members. If `x` is a pointer to a structure, then `*x` refers to that structure. So `*x` is that structure, and `*x` has members. So `(*x).personName` is a member. Also, `x[0]` is the same structure as `*x`, so `x[0].personName` is a member. – Eric Postpischil Nov 06 '21 at 12:12
  • 1
    @Michelin_Boi: `x+i` uses address arithmetic. If we have an array of structures, say array `A`, and the type of `x` is a pointer to that type of structure, then we can make `x` point to any element of the array. For example, `x = &A[3];` sets `x` to point to `A[3]`. The rule for address arithmetic is that, if `x` points to element `A[t]`, then `x+i` calculates a pointer that points to `A[t+i]`. After `x = &A[3];`, then `x+2` points to `A[5]`. Thus, if `x` points to `A[0]`, then `x+i` points to `A[0+i]`, which equals `A[i]`. So `x+i` points to `A[i]`, and `*(x+i)` **is** `A[i]`. – Eric Postpischil Nov 06 '21 at 12:15
  • Ohhhh I see, it makes so much sense now!!! thank you so much for taking the time to explain to me!! :> – Michelin_Boi Nov 06 '21 at 14:23
-1

However, I am rather confused why the Compiler asked me to use Dot Notation instead of Pointer Notation as I thought I passed in the address of the Struct into *idCard so it should be a pointer if I am not wrong?

Arrays are mostly just pointers to the first element in the array (except that the compiler may be aware of the array size).

Because arrays are mostly just pointers; for arrays of integers myInt = myIntArray[x]; is like myInt = *(myIntArray + x); - the pointer dereferencing is implied by array indexing. Note that to access a char in the middle of an int in an array, you could (not portably) use something like myChar = *((char *)(myIntArray + x)) + offset_of_char_in_int);; and this is a little bit like accessing a field inside an array of structures (in that they're both accessing something smaller within an array of larger things).

For arrays of structures; indexing the array causes dereferencing (just like it does for the array of integers); so myIDcardStruct = idCard[i]; is like myIDcardStruct = *(idcard + i);. Because array indexing has implied dereferencing, myIDcardStruct is not a pointer.

The -> operator is like adding the offset of the requested structure's field to the address, casting the address to the requested field's type, and then dereferencing. In other words myInt = myStructPointer->myIntField; is like myInt = (*myStructPointer).myIntField; which is like tempAddress = (void *)myStructPointer + offset_of_myIntField; myInt = *((int *)tempAddress);.

What this means is that if you have an array of structures (which is mostly a pointer to the first structure in the array), indexing the array causes the pointer to be implicitly dereferenced, and using -> also causes implicit dereferencing; and if you do both then you've (implicitly) dereferenced a pointer twice, which is too much dereferencing (because it's not a pointer to a pointer to a structure, or an array of pointers to structures). Because you only want it dereferenced once you have to choose between one implicit deference (array indexing) or the other implicit dereference (->); e.g. you can choose between myInt = idCard[i].nameCardID; or myInt = (idCard + i)->nameCardID;.

Of course the important thing is making code easy to read, and myInt = idCard[i].nameCardID; is easier to read than myInt = (idCard + i)->nameCardID;.

Brendan
  • 35,656
  • 2
  • 39
  • 66
  • We continually have to correct the notion that “arrays are pointers”, and writing “Arrays are mostly just pointers” does damage to that effort. It should not be in this answer. It is sufficient to explain that `idCard[i]` is a structure object, not a pointer to it, and therefore a member of the structure is accessed with `idCard[i].member`, not `idCard[i]->member`. – Eric Postpischil Nov 05 '21 at 11:48
  • @EricPostpischil: That effort is misguided (does more harm than good, especially when people are trying to understand what their code actually asks the CPU/hardware to do), and deserves damage. – Brendan Nov 05 '21 at 14:55
  • I have never thought about Arrays like this before and I don't think I fully understood everything. However, I thought it was an informative read and I will try to refer to both answers as I code more in the future!! Thank you :> – Michelin_Boi Nov 06 '21 at 07:44