I did not suggest to write things without using pointers, I suggested to make each thing that contains pointers also contain (much) more data than pointer.
Yep. The text editor example is still valid, although rather than running out of memory, having more data per node makes traversal faster, and thus the text editor more responsive. (In GUI editors, the problem is even more complex, since it boils down to not only finding the bounding rectangle for each displayed glyph, but also being able to discover the interglyph position given any relative 2D coordinate. Fortunately, windowing toolkits and widget toolkits typically provide that.)
Choosing an efficient data structure and algorithms typically makes an order of magnitude bigger difference than optimizing the same code at the instruction level. For machine-formatted text like HTML, CSS, obfuscated JavaScript et cetera, the text content may not contain any newlines or paragraph breaks at all, so just storing each line separately is inefficient, too: to insert or delete a single character, the entire file might have to be moved in memory because the entire file is essentially a single line, and that wreaks havoc with CPU and OS-level caching if the file is large, making everything on that core slower than necessary. Splitting at word boundaries may generate too many words, making traversal slow, too. There is no good solution that would work well in all situations, so instead you'll want something that can split large nodes and combine small nodes to more optimal sizes as their access patterns change.
(Interestingly, doing something similar for binary search trees –– balancing the tree instead of splitting and combining nodes to keep the tree structure close to optimal –– lead to
red-black tree data structures in the 1970s.)
The exception is data structures describing graphs and networks, where the pointer itself is the data.
As an example, consider the C code I posted about a month ago implementing a
dependency manager by describing the dependencies as edges in a directed graph. It has two abstract data structure types: one for fast lookup by name (hash table entries forming a linked list, payload being a pointer to the dependency graph node, the DJB XOR2 hash of the name, and the name as a string), and the other to describe each node, consisting of three or more pointers (next in two unrelated linked lists, a reference to the name, and any number of directed edges to other nodes), a mutable unsigned integer (tag) used during tree traversal, and the number of unfulfilled dependencies (edges) from this node. As the pointers are the most interesting data in the nodes, the nodes consist mostly of pointers.
Some of the discussion in that thread following the example explains how sets of such data structures can be efficiently stored in pre-allocated arrays. I first encountered those in scientific Fortran code, so the technique is decades old already, and well tested in practice in terms of reliability and efficiency.
If we listed all edges in a single one-dimensional array (of unsigned integer values), with the edges sharing the same source consecutive in the array, with each such consecutive set preceded by the number of edges in the set (and optionally the source edge), we'd have a
Verlet list, first described by Loup Verlet in 1967. It is not as amenable to editing (deletion or masking out being important for the dependency graph processing in the example above), but if one uses signed integers with zero reserved for padding and negative values referring to "deleted" targets, and only positive non-zero values to identify each node, it works well even for the abovementioned dependency graph.
I personally don't see any big difference in the Verlet list/array approach and one using C99 structures as nodes with a flexible array member containing pointers to the targets myself. To me, that difference is just a practical implementation detail, and translating code using one to code using the other is more or less just a mechanical translation and not a creative one. The important thing to me is the cost of access. Whether the code uses pointers or element indexes or something else is irrelevant. What is relevant is the amount of practical work needed (at the machine code level) to arrive at the desired target, in optimal, typical, and pessimal (worst-case) cases. (It is also why I prefer to examine
median access time instead of
average access time. Average is skewed by outliers and thus not at all useful to me, whereas median tells the maximum time taken in at least 50% of the cases. Depending on the amount of outliers due to noise and testing system behaviour in general, 85%/95%/99% limits can be even more useful and informative.)