Pointers and 2D-arrays in C

Pointers and 2D-arrays in C

When taking the Engineering or CS undergrad path, like 1+1 leads to 2 (let's keep it simple here, shall we?), students will take C as their first programming language. Good old TurboC days. Well, once they get to face pointers, at first, hell comes to Earth (for most of them).

Pointers are cool! They allow you to play directly with memory space! But, as uncle Ben has already said, "with great power comes great responsibility". That being said, you should take care when dealing with pointers. Possible consequences of bad pointers usage can be memory leakage or a incredibly unstable application, just to say an example. If you are note careful enough, finding out that you left pointers hanging out there after they're not useful anymore, or that you have lots of uninitialized pointers can cause you a lot of trouble!

In addition, when dealing with arrays, things can get nasty in terms of how you write the code to access the contents of that desired pointer. Extra dimension added to the array will increase the complexity of how you will write your code to access it, especially if you are willing to pass that array to a function. In this case, you'll want to pass a reference to the array, NOT copy it all to the function, as this would be a waste of resources.

Let's imagine a single integer:

int x = 10;
        

We can define a pointer to this integer and make it point to it:

int *ptr_int; /* Pointer to an int */
ptr_int = &x; /* Pointer points to that int (receives the address) */
        

So, now that your pointer has the address of that int (& operator), it can be de-referenced to give you the contents of that address it points to:

fprintf(stdout,"%d", *ptr_int);
        

Now, if you think of an array, try to picture that structure in memory. Yes! It is flat! A sequential allocation of positions of the same type. So, in order to create an array of integers, you just need to write:

int array[3] = { 1,2,3 }; /* an array of 3 integers */
        

How would you declare a pointer for an array of integers? Now C starts playing with its notations. If you thought of int *ptr[3]; you are wrong! That is not an pointer to an array of integers, but an array of pointers to integers! So, instead of holding 3 integers, this array holds 3 memory addresses for int values.

To have a pointer to an array of integers, you would simply use a pointer!

int array[3] = { 1,2,3 }; /* an array of 3 integers */
int *ptr;                 /* Pointer to an 1D-array of integers */

        

Another cool thing is that when dealing with arrays, they come down to memory addresses (pointers!). So if you want to make the pointer point to that array and use it, there is no need for the & operator at this time, as we are using the address directly:

int array[3] = { 1,2,3 }; /* an array of 3 integers */
        
 
int *ptr;                 /* Pointer to an 1D-array of integers */

/* Makes ptr points to the same location array points to!*/
ptr = array;

/* Using arrays index notation */

        
fprintf(stdout, "First element: %d\n", ptr[0]); /* Prints 1 */
fprintf(stdout, "First element: %d\n", ptr[1]); /* Prints 2 */
        
fprintf(stdout, "First element: %d\n", ptr[2]); /* Prints 3 */

/* Using pointers arithmetics notation */
fprintf(stdout, "First element: %d\n", *(ptr + 0)); /* Prints 1 */
fprintf(stdout, "First element: %d\n", *(ptr + 1)); /* Prints 2 */
fprintf(stdout, "First element: %d\n", *(ptr + 2)); /* Prints 3 */
        

Now, let's think of a Matrix. A Matrix is an array of one or more 1D arrays. The same logic above is used to access its elements. Consider a square 2DArray int 2DArray[2][2] as follows:

int 2DArray[2][2] = { {0,1}, {2,3}};
        

Its memory representation is linearly consecutive, from the computer's point of view. 2DArray: [0][1][2][3]

That being said, we can use a pointer to an array of ints that will be able to traverse each of the arrays of the 2DArray, just adding a "new line" after each array, so we can reproduce the visualization of the 2DArray.

In addition, these are how to point to the above 2DArray elements:

 2DArray   --> Whole 2D Array
*(2DArray) --> First ROW of the 2D array

Acessing rows: 
*(2DArray + 0) --> Same as *(2DArray)
*(2DArray + 1) --> Second ROW of the 2D array
*(2DArray + N) --> Nth ROW of the 2D array

Acessing columns: 
*( *(2DArray + 0) + 0) --> Points to 2DArray[0][0]
*( *(2DArray + 0) + 1) --> Points to 2DArray[0][1]
*( *(2DArray + 1) + 0) --> Points to 2DArray[1][0]
*( *(2DArray + 1) + 1) --> Points to 2DArray[1][1]


        

Here is a sample program to illustrate what we have been talking about throughout this post.

mkdir -p src/{1,2}d
touch src/{{CMakeLists.txt,main.c,includes.h},{1d/1d_arrays.{c,h},2d/2d_arrays.{c,h}}}

        


CMakeLists.txt file:

# Just set policy CMP0054 to NEW to avoid CMP0054 policy violations
cmake_policy(SET CMP0054 NEW)


# Minimum CMake Version
cmake_minimum_required(VERSION 3.10)


# Project name
set(PROJECT_NAME Arrays_Study)
project(${PROJECT_NAME} C CXX)


# Where to find includes
include_directories(?
? ? ${PROJECT_SOURCE_DIR}/?
? ? ${PROJECT_SOURCE_DIR}/1d?
? ? ${PROJECT_SOURCE_DIR}/2d?
)


# additional code as shared libs
add_library(1d SHARED 1d/1d_arrays.c)
add_library(2d SHARED 2d/2d_arrays.c)


# the main executable
add_executable(arrays_study main.c)


# links additional code with main target 

        
target_link_libraries(arrays_study 1d 2d)

        

includes.h file:

#ifndef _INCLUDES_H_
#define _INCLUDES_H_
#include <stdio.h>
#include <stdlib.h>


/* Square matrix size */
#define _size 3


/* Beautify arrays printing ;) */
#define _OPEN_CHAR_ '|'
#define _CLOSE_CHAR_ '|'


        
#endif
        

main.c file:

#include "includes.h"
#include "1d/1d_arrays.h"
#include "2d/2d_arrays.h"


int main
(int argc, char *argv[]) 
{
    /* A 1D array */
    int Array1D[_size] = {1,2,3};


    /* A 2D array */
    int Array2D[_size][_size] = {
        {1,2,3},
        {4,5,6},
        {7,8,9}
    };


    fprintf(stdout, "Printing a 1D Array\n");
    print_1d_array(&Array1D, _size);


    fprintf(stdout,"\n");


    fprintf(stdout, "Printing a 2D Array\n");
    print_2d_array(Array2D, _size);
    
    exit(EXIT_SUCCESS);
        
}
        

1d_arrays.h:

#ifndef _1D_ARRAYS_
#define _1D_ARRAYS_


/* Prints 1D arrays
 * Args:
 *  a pointer to an array of ints 
 *  size of that array
 */
void print_1d_array (int (*array)[], int size);


        
#endif
        

1d_arrays.c:

#include "../includes.h"
#include "1d_arrays.h"


void print_1d_array
(int (*_array)[], int size)
{
    int (*ptr)[size] = _array;
    
    fprintf(stdout, "%c ", _OPEN_CHAR_);
    for (int i=0; i < size; i++)
        fprintf(stdout, "%d ", (*ptr)[i]);
        
    fprintf(stdout, "%c", _CLOSE_CHAR_);        
    fprintf(stdout, "\n");
        
}
        

2d_arrays.h:

#ifndef _2D_ARRAYS_
#define _2D_ARRAYS_


/* Prints 1D arrays
 * Args:
 *  a pointer to an array of ints 
 *  size of that array
 */
void print_2d_array (int(*_matrix)[], int size);


        
#endif
        


2d_arrays.c:

#include "../includes.h"
        
#include "2d_arrays.h"


        
void print_2d_array
(int (*_matrix)[], int size)
{
    /* Points to the base address of the 2D array */
    int (*ptr)[size] = _matrix;
    
    for (int i=0; i < size; i++) {
            fprintf(stdout, "%c ", _OPEN_CHAR_);
        for (int j=0; j < size; j++ ) 
            /*                           line i, row j */
            fprintf(stdout, "%d ", *( *(ptr + i) + j));
        fprintf(stdout, "%c", _CLOSE_CHAR_);
        fprintf(stdout, "\n");
    }
}

        

Building the program:

cd src           # if not already there
mkdir build 
cd build
cmake ../        # of course you'll need cmake, make and gcc
make 
        

When running, it simply prints the two arrays (1D and 2D), but at this point you should understand pointers and arrays :-)

./arrays_study?

Printing a 1D Array
| 1 2 3 |

Printing a 2D Array
| 1 2 3 |
| 4 5 6 |

        
| 7 8 9 |
        

I hope this can be of any help.

-- FIN --

Rafael de Oliveira Ribeiro

Senior IP Network Engineer and Consultant

4 年

Nice one, Gabriel M.! Pointers were source of pain when learning C! Interesting that the first programming languages I learned were quite different: Basic when a kid, Pascal plus Assembly on vocational school. Tertiary studies began with FORTRAN and Assembly again - only at the end I was exposed to some C! Now it's just Python :)

要查看或添加评论,请登录

Gabriel M.的更多文章

  • Docker 101

    Docker 101

    A (tiny) introduction to Docker. If you want to get your hands dirty with some Docker content, this quick introduction…

  • Building custom kernels for Linux + updating the system firmware.

    Building custom kernels for Linux + updating the system firmware.

    In this post I'll show you how you can replace your current Linux kernel with a new one built entirely from the…

  • Debian complained about missing firmware during installation? Add missing 'non-free' firmware to installation image! :)

    Debian complained about missing firmware during installation? Add missing 'non-free' firmware to installation image! :)

    If you have installed Debian, you might have faced the screen below: And probably got very frustrated, because your…

  • Using Traps in Bash Scripts

    Using Traps in Bash Scripts

    Imagine that you have a script to perform some critical operation, one that would render the system completely unusable…

    2 条评论
  • Safer Bash Scripting Tips

    Safer Bash Scripting Tips

    I hope you are all well and safe. As "stay safe" is the most used expression during this COVID-19 period, I thought it…

    1 条评论
  • Linux Kernel Inotify Subsystem

    Linux Kernel Inotify Subsystem

    When dealing with Unix-style filesystems there must be a data structure that is capable of describing an object from…

  • Linux File I/O

    Linux File I/O

    When using system calls for dealing with file I/O, open(), read(), write() and close() are the four functions used to…

  • Shifting bits in C

    Shifting bits in C

    Have you ever asked yourself how much memory space do you waste when writing your code? Sometimes you just need a…

  • Improving your Linux box security

    Improving your Linux box security

    Did you know that more than never, during these quarantine days, there is a lot more malicious activities undergoing…

  • Build UnrealEngine on Linux, making it use less disk space! :)

    Build UnrealEngine on Linux, making it use less disk space! :)

    If you are playing with the amazing Unreal Engine on your Linux box, you might have noticed that the final size after…

社区洞察

其他会员也浏览了