arrays
strings
dynamic sizing
programming
coding tutorials

How do I declare an array of strings with an unknown size?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If you do not know in advance how many strings you need to store, a fixed-size array is usually the wrong first data structure. In many languages, arrays require a size at allocation time, which means you would otherwise have to guess, over-allocate, or keep copying into larger arrays as more strings arrive.

The usual solution is to collect values in a dynamic container first and convert to an array only if some later API really requires one. That pattern is simpler, safer, and usually faster than manual resizing.

Use a Dynamic Container First

Different languages solve this with different standard types:

  • C# uses List<string>
  • Java uses ArrayList<String>
  • C++ uses std::vector<std::string>
  • JavaScript arrays are already dynamic

The common idea is the same: grow the collection naturally while you discover the data, then materialize a final array only if you need one.

C# Example

In C#, the idiomatic answer is List<string>:

csharp
1using System;
2using System.Collections.Generic;
3
4var names = new List<string>();
5
6names.Add("Alice");
7names.Add("Bob");
8names.Add("Carla");
9
10string[] finalArray = names.ToArray();
11Console.WriteLine(string.Join(", ", finalArray));

If the downstream API accepts IEnumerable<string> or List<string>, there may be no reason to convert to string[] at all.

Java Example

Java uses the same pattern with ArrayList:

java
1import java.util.ArrayList;
2import java.util.List;
3
4public class Main {
5    public static void main(String[] args) {
6        List<String> values = new ArrayList<>();
7        values.add("one");
8        values.add("two");
9        values.add("three");
10
11        String[] array = values.toArray(new String[0]);
12        System.out.println(String.join(", ", array));
13    }
14}

Again, the important point is that the list grows dynamically while the final array is only created at the boundary where it is actually needed.

C++ Example

In C++, use std::vector<std::string>:

cpp
1#include <iostream>
2#include <string>
3#include <vector>
4
5int main() {
6    std::vector<std::string> values;
7    values.push_back("alpha");
8    values.push_back("beta");
9    values.push_back("gamma");
10
11    for (const auto& value : values) {
12        std::cout << value << '\n';
13    }
14}

std::vector is the standard growable sequence container and is the natural replacement for a fixed-size string array when the size is unknown at first.

Low-Level Languages Need Manual Resizing

If you are working in plain C or another low-level environment, you may need to grow the array manually:

c
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5int main(void) {
6    char **items = NULL;
7    size_t count = 0;
8
9    const char *source[] = {"red", "green", "blue"};
10    size_t source_count = sizeof(source) / sizeof(source[0]);
11
12    for (size_t i = 0; i < source_count; ++i) {
13        char **tmp = realloc(items, (count + 1) * sizeof(char *));
14        if (!tmp) return 1;
15        items = tmp;
16
17        items[count] = malloc(strlen(source[i]) + 1);
18        strcpy(items[count], source[i]);
19        count++;
20    }
21
22    for (size_t i = 0; i < count; ++i) {
23        puts(items[i]);
24        free(items[i]);
25    }
26    free(items);
27}

This works, but it shows why dynamic containers from standard libraries are usually the better first choice when they are available.

Common Pitfalls

The biggest mistake is allocating a fixed array too early and then repeatedly copying into larger arrays every time a new string arrives. That makes the code more complex than necessary.

Another common issue is converting the dynamic collection to an array inside a loop instead of only once at the API boundary. That creates needless allocations.

Developers also confuse reserved capacity with the current number of stored elements. A collection may have room for more items without actually containing them.

Finally, do not forget input cleanup. If strings come from users or files, it is often worth trimming or validating them before storing them in the growable container.

Summary

  • If the number of strings is unknown, start with a dynamic container rather than a fixed array.
  • Use List<string>, ArrayList<String>, or std::vector<std::string> depending on the language.
  • Convert to an array only when another API explicitly requires one.
  • Low-level languages can resize manually, but that is more error-prone than standard dynamic containers.
  • Keep collection growth and final array conversion as separate steps.

Course illustration
Course illustration

All Rights Reserved.