Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.
Check Distinct Array Elements
Detect duplicate values in 1-D arrays and 2-D matrices with clean, embedded-friendly C.
Duplicate values cause real bugs in firmware: two sensors answering to the same I2C address, two tasks sharing one priority slot, two CAN message IDs colliding in a lookup table. In this lecture of our free C programming course you will learn how to check distinct array elements in C, first for a 1-D array and then for a 2-D matrix. The idea is simple, but the way you write it decides whether it runs in microseconds or milliseconds on a small microcontroller. This free C tutorial keeps the focus on embedded C programming, so every method comes with its RAM and CPU cost.
What You Will Learn
- How to check distinct array elements in C using the pairwise comparison method
- How to return the exact positions of the first clash instead of a bare true or false
- A faster one-pass method that uses a small “seen” table, ideal for byte-sized IDs
- How to test a matrix for duplicates by walking it as one long row-major line
- What each approach costs in time and RAM, and which mistakes to avoid
Prerequisites
You should be comfortable with one-dimensional arrays, nested for loops, and passing an array to a function. Two-dimensional array declaration from the earlier lectures is needed for the matrix part. Any C11 compiler works; every program here was built with gcc -std=c11 -Wall -Wextra and produced zero warnings.
Why Check Distinct Array Elements in C?
An array is “distinct” when no value appears twice. That sounds like a classroom exercise, yet the same test shows up all over embedded work:
| Situation | What must be unique |
|---|---|
| I2C bus with many sensors | Every 7-bit device address |
| CAN or BLE firmware | Message IDs or handle numbers in a table |
| Pin multiplexing table | Each GPIO pin assigned only once |
| RTOS configuration | Task priorities or event flag bits |
| Quiz or lottery software | Drawn numbers, roll numbers, seat numbers |
Validating such tables at start-up, or in a unit test, catches configuration mistakes before they become strange field failures.
Method 1: Check Distinct Array Elements by Pairs
The direct way to check distinct array elements in C is to compare element 0 with all elements after it, then element 1 with all elements after it, and so on. You never compare an element with itself, and you never repeat a pair, so an array of n items needs exactly n(n-1)/2 comparisons.
Pairs examined for an array of 4 elements
| Outer index i | Inner index j | Pairs compared |
|---|---|---|
| 0 | 1, 2, 3 | 3 |
| 1 | 2, 3 | 2 |
| 2 | 3 | 1 |
| 3 | none | 0 |
| Total | 6 = 4 x 3 / 2 |
The program below goes one step further than a yes/no answer. It reports which two positions clash, which is far more useful when you are debugging a configuration table.
Method 1 and Method 2 together: ex51a.c
/* ex51a.c - are all elements of a 1-D array distinct? */
#include <stdio.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
/* Approach 1: compare every pair. Works for any int values. */
static bool find_duplicate(const int *a, size_t n, size_t *first, size_t *second)
{
for (size_t i = 0; i + 1 < n; i++) {
for (size_t j = i + 1; j < n; j++) {
if (a[i] == a[j]) {
*first = i;
*second = j;
return true;
}
}
}
return false;
}
/* Approach 2: one pass with a "seen" table. Only for small value ranges (bytes). */
static bool all_distinct_u8(const uint8_t *a, size_t n)
{
bool seen[256] = { false };
for (size_t i = 0; i < n; i++) {
if (seen[a[i]])
return false;
seen[a[i]] = true;
}
return true;
}
static void report(const char *label, const int *a, size_t n)
{
size_t i, j;
if (find_duplicate(a, n, &i, &j))
printf("%-10s: value %d repeats at index %zu and %zu\n", label, a[i], i, j);
else
printf("%-10s: all %zu elements are distinct\n", label, n);
}
int main(void)
{
int sensor_ok[] = { 12, 7, 33, 5, 21 };
int sensor_bad[] = { 12, 7, 33, 5, 7, 21 };
uint8_t node_ok[] = { 0x10, 0x22, 0x31, 0x44 };
uint8_t node_bad[] = { 0x10, 0x22, 0x10, 0x44 };
report("sensor_ok", sensor_ok, sizeof sensor_ok / sizeof sensor_ok[0]);
report("sensor_bad", sensor_bad, sizeof sensor_bad / sizeof sensor_bad[0]);
printf("node_ok : %s\n", all_distinct_u8(node_ok, 4) ? "distinct" : "duplicate found");
printf("node_bad : %s\n", all_distinct_u8(node_bad, 4) ? "distinct" : "duplicate found");
return 0;
}
How find_duplicate Works
Control flow of find_duplicate
- The outer loop condition is
i + 1 < ninstead ofi < n - 1. With an unsignedsize_tandn == 0, the expressionn - 1wraps around to a huge number and the loop would run off the array. Moving the1to the other side avoids that trap. - The parameter is
const int *abecause the function only reads the array. The compiler will now reject any accidental write. - The function hands back
firstandsecondthrough pointers. C functions return one value, so extra results travel through pointer parameters. sizeof sensor_ok / sizeof sensor_ok[0]computes the element count at compile time. This only works in the function where the array is declared, a point we study in detail in the lecture on array decay.
Method 2: A Seen Table for Embedded C
Pairwise comparison costs time that grows with the square of the array size. If the values are small, you can trade a little RAM for speed. Create a table with one flag per possible value, then walk the array once. The first time you meet a value you mark it; if you meet a marked value, you have found a duplicate.
The function all_distinct_u8 in the program above does this for byte-sized values, using a 256-entry bool table. It finishes in at most n steps. On a tight microcontroller you can shrink the table to 32 bytes by storing one bit per value inside eight uint32_t words, which is the usual bitmap trick.
Build and Run
gcc -std=c11 -Wall -Wextra -o ex51a ex51a.c
./ex51a
Expected output:
sensor_ok : all 5 elements are distinct
sensor_bad: value 7 repeats at index 1 and 4
node_ok : distinct
node_bad : duplicate found
Check Distinct Elements in a Matrix
A matrix is the same problem with a different address calculation. Row-major storage means a 3 x 4 matrix sits in memory as 12 integers in one unbroken line: all of row 0, then all of row 1, then all of row 2. If you number those cells 0 to 11, position p lives at row p / COLS and column p % COLS.
The same 3 x 4 matrix as a flat line of 12 cells
| Flat position p | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Row (p / 4) | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 2 | 2 | 2 | 2 |
| Column (p % 4) | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 |
With that mapping, a matrix check becomes the pairwise method again: take every pair of flat positions p < q and compare the two cells.
Program: ex51b.c
/* ex51b.c - are all elements of a matrix distinct? */
#include <stdio.h>
#include <stdbool.h>
#define COLS 4
/* Treat the matrix as one long row-major line of rows*COLS cells. */
static bool matrix_is_distinct(const int m[][COLS], int rows)
{
int total = rows * COLS;
for (int p = 0; p < total - 1; p++) {
for (int q = p + 1; q < total; q++) {
int pr = p / COLS, pc = p % COLS; /* flat position -> row, col */
int qr = q / COLS, qc = q % COLS;
if (m[pr][pc] == m[qr][qc]) {
printf(" clash: (%d,%d) and (%d,%d) both hold %d\n",
pr, pc, qr, qc, m[pr][pc]);
return false;
}
}
}
return true;
}
int main(void)
{
int good[3][COLS] = {
{ 4, 9, 1, 7 },
{ 3, 8, 2, 6 },
{ 5, 12, 10, 11 }
};
int bad[3][COLS] = {
{ 4, 9, 1, 7 },
{ 3, 10, 2, 6 },
{ 5, 12, 10, 11 }
};
printf("matrix good:\n");
printf(" %s\n", matrix_is_distinct(good, 3) ? "all distinct" : "has duplicates");
printf("matrix bad:\n");
printf(" %s\n", matrix_is_distinct(bad, 3) ? "all distinct" : "has duplicates");
return 0;
}
The parameter const int m[][COLS] leaves the first dimension empty but must name the second. The compiler needs COLS to turn m[r][c] into the address m + r * COLS + c. The row count travels as a separate argument.
The “bad” matrix, with the clashing cells highlighted
| Row | Col 0 | Col 1 | Col 2 | Col 3 |
|---|---|---|---|---|
| 0 | 4 | 9 | 1 | 7 |
| 1 | 3 | 10 | 2 | 6 |
| 2 | 5 | 12 | 10 | 11 |
gcc -std=c11 -Wall -Wextra -o ex51b ex51b.c
./ex51b
Expected output:
matrix good:
all distinct
matrix bad:
clash: (1,1) and (2,2) both hold 10
has duplicates
Cost Comparison
| Elements (n) | Pairwise comparisons | Seen-table steps |
|---|---|---|
| 10 | 45 | 10 |
| 100 | 4,950 | 100 |
| 1,000 | 499,500 | 1,000 |
For a 20-entry configuration table the pairwise version is perfectly fine and needs no extra RAM. For a stream of thousands of byte-sized samples, the seen table wins by a wide margin. A third option, sorting a copy of the array and comparing neighbours, costs about n log n steps and works for any value range, but it needs a spare copy of the data.
Real-World Uses
- Start-up self-check: loop over a table of peripheral addresses and halt with an error code if two entries match.
- Unit tests: assert that a generated ID list contains no repeats.
- Data validation: reject a packet whose list of requested channel numbers repeats a channel.
Common Mistakes and Troubleshooting
- Starting the inner loop at j = i. Every element equals itself, so the function would report a duplicate every time.
- Comparing only neighbours.
a[i] == a[i+1]finds duplicates only in a sorted array. - Dividing by ROWS instead of COLS. The flat position to row and column mapping always uses the column count.
- Using a seen table with unchecked values. A value of 300 in a
bool seen[256]table silently corrupts memory. - Measuring size inside a function.
sizeof aon a parameter gives the pointer size, so always pass the element count.
Best Practices to Check Distinct Array Elements
- Mark read-only parameters
const. - When you check distinct array elements, return the positions of the clash, not only a flag, so error messages are useful.
- Choose the algorithm from the data range: pairwise for small tables, seen table for byte-sized values, sort-and-scan for everything else.
- Treat data from UART, SPI or the network as untrusted. Check that the length fits your table before you use it as an index.
Summary and Key Takeaways
- To check distinct array elements in C, compare each pair once, never an element with itself.
- The pairwise method needs n(n-1)/2 comparisons and no extra memory.
- A seen table needs one pass but extra RAM and a bounded value range.
- A matrix is just a 1-D line in row-major order; use
p / COLSandp % COLSto find a cell.
Knowing how to check distinct array elements in C is a small skill with a big lesson: the same task can be solved with very different time and memory costs, and good embedded C programming means picking the cost that fits your hardware. In the next lecture we move to square matrices and add up their two diagonals.
Frequently Asked Questions
How do I check distinct array elements in C without extra memory?
Use two nested loops with the inner index starting at i + 1. It needs no extra arrays, only a few integer variables.
What is the time complexity of the pairwise duplicate check?
It is O(n squared) in the worst case, which happens when all elements are distinct, because every pair gets compared.
When should I use the seen table instead?
When values come from a small known range such as bytes. It runs in O(n) time at the price of a table sized to the value range.
Can I sort the array first?
Yes. After sorting, any duplicates sit next to each other, so one pass comparing neighbours finds them. Sort a copy if you must keep the original order.
Why is the matrix parameter written const int m[][COLS]?
The compiler needs the column count to compute addresses, while the row count can stay open. The const keyword promises the function will not modify the matrix.
Does this work for floating-point arrays?
The logic is the same, but comparing floats with == is unreliable after calculations. Compare with a small tolerance instead.
Keep Building Your Embedded C Skills
This lecture is part of the EmbeddedPathashala free C programming course, a free C tutorial written for students who want to write solid embedded C programming code. Compile every program yourself, change the data, and break things on purpose.
Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.

2 Comments