Home > Back-end >  Look for characters in a specific location of 2D array with pointers
Look for characters in a specific location of 2D array with pointers

Time:05-30

I have been playing around with pointers and arrays and I have successfully come up with this code that does what I intend to. The following code looks for a specific character in a specific location of the array.

#include <stdio.h>

int main()
{
    int i = 0;
    int arraySize = 5;
    int location = 2;

    char arr[5] = { 'a', 'b', 'c', 'd', 'e' }; 
    char *ptr = arr; //same as char *ptr = &arr[0]

    for (i = 0; i < arraySize; i  )
    {
        if (ptr[location] == 'c')
        {
            printf("found");
            i = arraySize   1;
        }
    }

    return 0;
}

Now I want to try to find a specific character in a 2D array and I do not fully understand the process of how to do it, I had researched a bit but I am not really sure how to search for it.

I have written a partial code and I believe that I will need to add a second for loop to iterate through the other direction of the array. Although it does not work as I believe I have to modify the pointer but not too sure how.

#include <stdio.h>

int main()
{
    int i = 0;
    int j = 0;
    int arraySize = 5;
    int location = 2;
    int location2 = 2;

    char arr[5][5] = { {'a','b','c','d','e'}, {'g','h','c','j','k'} }; 
    char *ptr = arr;

    for (i = 0; i < arraySize; i  )
    {
        for (j = 0; j < arraySize; j  )
        {
            if (ptr[location][location2] == 'c')
            {
                printf("found");
                i = arraySize   1 ;
            }
        }
    }

    return 0;
}

I have little knowledge of coding so please be patient! Any help is greatly appreciated.

CodePudding user response:

There are some issues in your programs:

  • you test if ptr[location] == 'c' but you should instead use index i:

      if (ptr[i] == 'c')
    
  • you cause the loop to exit by patching the loop index variable i with i = arraySize 1; This is considered sloppy, confusing and error prone. You should just use a break statement.

In your code, there is no need for a pointer, but if you pass the array to a function, this function will receive a pointer to the first element of the array.

Here is a modified version:

#include <stdio.h>

int find_char(char *ptr, int size, char ch) {
    for (int i = 0; i < size; i  ) {
        if (ptr[i] == ch) {
            printf("found '%c' at index %d\n", ch, i);
            return 1;
        }
    }
    return 0;
}

int main() {
    char arr[] = { 'a', 'b', 'c', 'd', 'e' }; 
    int arraySize = sizeof(arr) / sizeof(*arr);

    if (!find_char(arr, arraySize, 'c')) {
        printf("not found\n");
    }
    return 0;
}

The case of a 2D array is more tricky: if you pass the array to a function, the argument must be defined as a pointer to an array of arrays. There are 2 ways to specify such a pointer:

  • as a pointer to an array of arrays of a fixed size:

    int find_char(int rows, char (*ptr)[5], char ch)
    
  • as a pointer to an array of arrays of a specified variable size: this possibility was added in C99 but is not supported by all compilers:

    int find_char(int rows, int cols, char (*ptr)[cols], char ch)
    

Here is a modified version using this C99 approach:

#include <stdio.h>

int find_char(int rows, int cols, char (*ptr)[cols], char ch) {
    for (int i = 0; i < rows; i  ) {
        for (int j = 0; j < cols; j  ) {
            if (ptr[i][j] == ch) {
                printf("char '%c' was found at array[%d][%d]\n", ch, i, j);
                return 1;
            }
        }
    }
    return 0;
}

int main() {
    char arr[][5] = { { 'a', 'b', 'c', 'd', 'e' },
                      { 'g', 'h', 'c', 'j', 'k' } }; 
    int rows = sizeof(arr) / sizeof(*arr);
    int cols = sizeof(arr[0]) / sizeof(*arr[0]);

    if (!find_char(rows, cols, arr)) {
        printf("not found\n");
    }
    return 0;
}

CodePudding user response:

You have to be careful here. A 2D array in C is an array-of-arrays. Meaning arr[x][y] is an array of x arrays of y elements each. This is important for pointer use with 2D arrays.

In C, when an array is accessed, it is converted to a pointer to the first element. See C18 Standard - 6.3.2.1. So when you access arr in your code, it is converted to a pointer to the first array.

What type is the pointer? It is a pointer-to-array-of char[5]. A pointer-to-array char[5] named ptr is declared:

char (*ptr)[5];

(note: the parenthesis ARE important. Due to operator-precedence [ ] has higher precedence, so if declared char *ptr[5]; you do not have a pointer-to-array, but instead have an array-of-pointers. Adding the parenthesis around (*ptr) specifies the type pointer is evaluated before [ ] resulting in a pointer-to-array)

In order to access a specific character in the ith array in arr, you can use ptr[i][j] (which is equivalent to *(*(ptr i) j), but is the preferred form for readability). You can also simply declare and use a separate pointer to access each element of the ith array, such as char *p = ptr[i];

How does the type work? Recall, ptr is a pointer-to-array. The [ ] acts as a dereference of the pointer just as *ptr would. (technically *ptr is *(ptr 0) or in preferred form ptr[0]). So when you dereference ptr to get the ith array, the resulting type will be char [5]. Since it is an array type, on access 6.3.2.1 applies resulting in the type being pointer-to char.

Putting it altogether, and using an additional index on ptr to access each character, and allowing you to specify the character to search for as the first argument to your program (default 'c' if no argument is given), you could do:

#include <stdio.h>

#define ASIZE 5   /* if you need a constant, #define one (or more) */

int main (int argc, char **argv)
{
    char arr[][ASIZE] = { {'a','b','c','d','e'},    /* 2D array of char */
                          {'g','h','c','j','k'} }, 
         (*ptr)[ASIZE] = arr,                       /* pointer to array */
         find = argc > 1 ? *argv[1] : 'c';          /* char to find */
    int nrows = sizeof arr / sizeof *arr,           /* no. of rows */
        found = 0;                                  /* found flag */
    
    for (int i = 0; i < nrows; i  ) {               /* loop over arrays */
        for (int j = 0; j < ASIZE; j  ) {           /* loop over chars */
            if (ptr[i][j] == find) {                /* compare */
                printf ("found '%c' in array %d within arr\n", find, i   1);
                found = 1;                          /* set found flag */
                goto done;                          /* break nested loops */
            }
        }
    }
    done:;
    
    if (!found) { /* handle char not found */
        printf ("character '%c' - not in arr\n", find);
    }
}

(note: the only way to directly break nested loops is to use the goto statement)

As mentioned above, the pointer notation equivalence can be used for the comparison. So the following is equivalent (just harder to read):

            if (*(*(ptr   i)   j) == find) {        /* compare */

Often, it is simpler to use a separate pointer to iterate over the objects in the row-arrays. A quick rewriting of the loops can be done as follows:

    for (int i = 0; i < nrows; i  ) {               /* loop over arrays */
        char *p = ptr[i];
        for (; p < ptr[i]   ASIZE; p  ) {           /* loop over chars */
            if (*p == find) {                       /* compare */
                printf ("found '%c' in array %d within arr\n", find, i   1);
                found = 1;                          /* set found flag */
                goto done;                          /* break nested loops */
            }
        }
    }
    done:;

Which from C99 on allows you to declare the loop variable within the loop declaration allowing you to rewrite the loop as:

        /* loop over chars */
        for (char *p = ptr[i]; p < ptr[i]   ASIZE; p  ) {
            ...
        }

Example Use/Output

Regardless of which notation you use, the results are the same, e.g.

$ ./bin/findcharin2Darr
found 'c' in array 1 within arr

If the requested character isn't in the array:

$ ./bin/findcharin2Darr f
character 'f' - not in arr

Or locating a character in the second row:

$ ./bin/findcharin2Darr g
found 'g' in array 2 within arr

Look things over and let me know if you have further questions.

  •  Tags:  
  • c
  • Related