Search code examples
cstringmultidimensional-arraystrcmp

Strcmp 1-D array vs 2-D array in c


When using strcmp function (in the string.h library) , passing a 2-D character array as a parameter comparison , there is a need to add the ampersand symbol like

&mainlist[i][0]

otherwise like

mainlist[i][0]

there's an error

warning: passing argument 1 of 'strcmp' makes pointer from integer without a cast [-Wint-conversion]

versus when passing 1-D character array as a parameter comparison , its enough

mainlist[i]

without ampersand symbol. How come?

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

#define FOUND 1
#define NOT 0

int main()
{
   char mainlist[5][10] = {"test1", "test2", "test3", "test4", "test5"};
   int flag, i;
   flag = NOT;
   char myname[50];
   printf("Enter ur name.\n");
   scanf("%s", myname);
   for(i = 0; i < 5; i++)
   {
      if(strcmp(mainlist[i], myname)== 0) //vs if(strcmp(&mainlist[i][0]), myname)==0)
      {
         flag = FOUND;
         printf("Your name was found welcome.\n");
         break;
        
      }
   }
   if(flag == NOT)
   {
      printf("Your name was not found .\n");
   }
}

Solution

  • When using strcmp function (in the string.h library) , passing a 2-D character array as a parameter comparison , there is a need to add the ampersand symbol like: &mainlist[i][0]

    Each use of an array index reduces a dimension of the array. mainlist is a 2D char array, mainlist[i] is a 1D char array, and mainlist[i][0] is a single char.

    strcmp() requires its arguments to be pointers to the first char in the strings to compare, that's all that string are. mainlist[i][0] is a single char, like 't', so that won't work. &mainlist[i][0] is its address, a pointer to the first char in the string, so that works.

    On the other hand, when you give an array is given as a function argument, what actually gets passed is a pointer to the first element of the array. For array mainlist[i], that's &mainlist[i][0]. Look familiar? This is presumably one of the key points you overlooked.


    char mainlist[5][10] = {"test1", "test2", "test3", "test4", "test5"};
    

    Looks like this in memory.

              1         2         3         4
    01234567890123456789012345678901234567890123456789
    test1_____test2_____test3_____test4_____test5_____
    ^
    |
    mainlist
    

    Where _ represents a null byte. mainlist points at the memory containing the first character.

    When you ask for mainlist[i] that says to add i * 10 to the address of mainlist and dereference it. You can literally write *mainlist + i * 10

              mainlist[1]         mainlist[3]
              |                   |
              v                   v
              1         2         3         4
    01234567890123456789012345678901234567890123456789
    test1_____test2_____test3_____test4_____test5_____
    ^                   ^                   ^
    |                   |                   |
    mainlist[0]         mainlist[2]         mainlist[4]
    

    A pointer to the first character of a string is what a string is in C, a char *. Each of these are a string, a 1-D array, suitable for passing to strcmp.

    mainlist[i][0] says to take the address of mainlist[i], add 0, and dereference it. The result is a char like t. This doesn't work with strcmp because it takes a pointer. The integer in "warning: passing argument 1 of 'strcmp' makes pointer from integer without a cast [-Wint-conversion]" is the char because characters are just integers and strcmp tried to use that integer as a char pointer.

    &mainlist[i][0] says to make a pointer to that char, so we're back to a char * or mainlist[i].

    Demonstration.

    mainlist[i] is almost always preferable to &mainlist[i][0]. However, it does have its uses. There are times when you want to skip the first few characters of a string, and you can do so without copying nor modifying the string. For example, &mainlist[2][2] is "st3". It's a pointer to mainlist[2] + 2.

                          &mainlist[2][2]
                          |
                          v
    01234567890123456789012345678901234567890123456789
    test1_____test2_____test3_____test4_____test5_____
                        ^
                        |
                        mainlist[2]
    

    C will read from the pointer until the null byte.