Each device on an I2C bus needs to have a unique address. There can't be two devices with address 0x42 for example. Here's a list of I2C addresses for various target devices:
So what happens if more than one device has the same address? It's sort of undefined. It may be that all devices will respond the same, like "hey every 0x42 device, do a software reset". But since devices need to also write to the bus, there can be conflicts.
How do you deal with address conflicts? There are various approaches. Let's take a look at them, starting with the easiest option.
Some, but not all, target devices allow for setting one or more alternate address. Some only have two options. Some have many more. And of course, some are fixed to just one address. Details vary, so one must consult datasheets for specifics.
Most devices that have this option will provide dedicated pins that configure the alternate I2C addresses. These may be broken out to the header pins, but a more common approach used on Adafruit breakouts is to provide solder pads. For example, here is the solder pad on the BMP280 breakout for setting the alternate address:
As another example, the PCA9685 PWM driver allows setting up to 62 different addresses! This requires many more solder pads:
This is the simplest solution for dealing with I2C address conflicts if alternate addresses can not be set. An I2C multiplexer acts like a signal switcher. There is one input which gets connected to the controller's I2C port. Then, there are multiple outputs that get connected to the target devices. Only one output is active at any given time. Therefore, target devices with the same address can be place on the different outputs. And the host only sees one at a time. The output can be changed to talk to any of the other attached devices.
The TCA9548A is an example of an I2C multiplexer:
Checkout this guide for example usage of a TCA9548A multiplexer:
This is not a beginner friendly approach.
Some controllers may have more than one I2C bus. The Raspberry Pi Pico, for example, has two. So another idea is to use a separate I2C port for each target device. While this generally works, it can be problematic. It does not scale well. And depending on how libraries are written, switching between buses may require extra work - i.e. more complex code.