Structures

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

Written against MATLAB R2026b. The sessions below were run in GNU Octave 11.3.0 (MATLAB code that Octave also accepts) and show Octave’s output; MATLAB displays structures in a different layout (struct with fields:). Where an error message is quoted from MATLAB it is labelled "not run here" or described rather than quoted, because messages vary between releases and Octave’s differ.

A structure groups related values under names called fields. Where a cell array (Cell Arrays) is accessed by position, a structure is accessed by name, which makes code that handles records readable: plate.nx says more than c{4}. Each field can hold any type and size, including another structure. A structure array holds several structures that share the same field names, one per element. Structures are the natural representation of configuration, of the output of jsondecode and readstruct, and of a record that you pass between functions.

Scalar structures

Dot notation creates a structure and its fields on assignment; there is no declaration step.

s.name = 'plate1';
s.size = [10 5];
s.bc.left = 100;
s.bc.right = 0;
s
fieldnames(s)

Octave 11.3.0 output:

s =

  scalar structure containing the fields:

    name = plate1
    size =

       10    5

    bc =

      scalar structure containing the fields:

        left = 100
        right = 0


ans =
{
  [1,1] = name
  [2,1] = size
  [3,1] = bc
}

The variable s is a scalar structure (a 1-by-1 structure array). The field bc holds a nested structure, reached with a second dot: s.bc.left is 100. If a field holds an array, ordinary indexing applies to the result, as in s.size(2), which is 5. The documentation’s Structure Arrays page builds the same idea with a patient structure whose fields are a name, a billing amount and a 3-by-3 matrix of test results.

You can also create a structure in one call with the function struct:

s = struct(field1, value1, field2, value2, ...)

Field names must begin with a letter and may contain letters, digits and underscores; they are case sensitive and cannot contain periods. Do not reuse the names of existing variables or functions as field names, to avoid confusion.

Dynamic field names

When the field name is only known at run time, wrap an expression in parentheses after the dot. The expression must return a character vector or a string scalar.

f = 'size';
s.(f)
s.(['n' 'ame'])

Octave 11.3.0 output: the first line prints 10 5 and the second prints ans = plate1. The same form creates a field (s.(name) = value) and works with a loop over a list of names, which replaces numbered variables such as plate1, plate2. A name built from user data, for example a sensor identifier, is only legal if it is a valid field name; matlab.lang.makeValidName turns arbitrary text into one. For lookup by arbitrary keys a dictionary is a better fit (Dictionaries and containers.Map).

Inspecting and changing the fields

Function Purpose

fieldnames(s)

Cell column of the field names

isfield(s, name)

True if name is a field; given a cell array of names, returns one logical per name

isstruct(x)

True if x is a structure

rmfield(s, name)

Returns the structure without that field (a name or a cell array of names)

orderfields(s)

Returns the structure with fields in alphabetical order (a second argument gives another order)

getfield(s, name), setfield(s, name, value)

Function forms of reading and writing a field; dot notation is shorter, but the functions help in code that builds the path as data

struct2cell(s), cell2struct(c, fields, dim)

Convert between a structure and a cell array of values

isfield(s, 'name')
isfield(s, {'name','nope','bc'})
s = rmfield(s, 'size');
fieldnames(s)'
t = struct('b',1,'a',2,'c',3);
t2 = orderfields(t);
fieldnames(t2)'

Octave 11.3.0 output: ans = 1, then 1 0 1, then the names name and bc after size is removed, and finally a, b, c for the reordered structure. rmfield fails if the field does not exist, so test with isfield first when it may be absent. The order of the fields is the order of creation, and it matters for display, for struct2cell and when you concatenate structures.

Structure arrays

Indexing a structure variable with a subscript creates an array. Each element is a structure with the same set of fields.

p(1).id = 1; p(2).id = 2; p(3).id = 3;
size(p)
[p.id]
[p.val] = deal(10,20,30);
{p.val}
ids = arrayfun(@(e) e.id*2, p)

Octave 11.3.0 output:

ans =

   1   3

ans =

   1   2   3

ans =
{
  [1,1] = 10
  [1,2] = 20
  [1,3] = 30
}

ids =

   2   4   6

Assigning to p(2).id when p does not exist creates p as a 1-by-2 array and gives the other elements empty fields. Three idioms matter:

  • Gather a field. p.id with a structure array is a comma-separated list (Comma-Separated Lists), so [p.id] concatenates the values into an array and {p.id} collects them in a cell array.

  • Assign a field of every element. [p.val] = deal(10,20,30) writes one value per element, and [p.val] = deal(0) the same value everywhere.

  • Apply a function per element. arrayfun(func, p) calls func on each element (each is a scalar structure); like cellfun it needs UniformOutput set to false when the results are not scalars.

Deleting an element uses p(2) = [], as for any array, and numel(p) counts the elements. Elements added later by p(end+1) = newElement must have the same fields in the same order.

The struct cell-value trap

The function struct treats a cell array given as a value as a request to create a structure array, one element per cell. This surprises people who want a cell array as the content of a single field.

u = struct('a', {1,2,3});
size(u)
w = struct('a', {{1,2,3}});
size(w)
class(w.a)
z = struct('a', {});
size(z)

Octave 11.3.0 output: size(u) is 1 3 (three elements, each with a a number), size(w) is 1 1 (one element, whose field a is the cell array {1,2,3}, and class(w.a) is cell), and size(z) is 0 0, an empty structure array that still has the field a. To store a cell array in a field, wrap it in a second pair of braces; to make an empty array that has fields but no elements, pass {} as the value. If several values are cells they must have the same size, otherwise struct fails (Octave 11.3.0: struct: dimensions of parameter 2 do not match those of parameter 4; MATLAB raises an error with its own text, not run here); a value that is not a cell is copied to every element.

Applying functions to fields: structfun

structfun applies a function to every field of a scalar structure, as cellfun does for cells.

st.x = 1; st.y = 2; st.z = 3;
structfun(@(v) v*10, st)
r = structfun(@(v) v*10, st, UniformOutput=false)
c = struct2cell(st)

Octave 11.3.0 output (run with the equivalent pair 'UniformOutput', false, because Octave does not accept the Name=Value form): a column 10 20 30; then r as a structure with fields x, y, z equal to 10, 20, 30; and c as a 3-by-1 cell array 1, 2, 3. By default the outputs of structfun are collected into a column vector, which needs scalar results; with UniformOutput set to false the result has the same field names as the input.

Heatflow: the plate configuration from JSON

The plate configuration of the heatflow scenario (The heatflow scenario) lives in plate.json. The function jsondecode turns a JSON object into a scalar structure, a JSON object with equal keys inside an array into a structure array (when all the elements have the same fields), and nested objects into nested structures.

txt = '{"width":0.5,"height":0.3,"nx":50,"ny":30,"boundary":{"left":100,"right":0},"sensors":[{"id":"S1","x":0.1,"y":0.1},{"id":"S2","x":0.4,"y":0.2}]}';
plate = jsondecode(txt);
plate.boundary.left
size(plate.sensors)
plate.sensors(2).id
for k = 1:numel(plate.sensors)
  fprintf('%s at (%.1f, %.1f)\n', plate.sensors(k).id, plate.sensors(k).x, plate.sensors(k).y);
end

Octave 11.3.0 output:

ans = 100
ans =

   2   1

ans = S2
S1 at (0.1, 0.1)
S2 at (0.4, 0.2)

The sensors become a 2-by-1 structure array, each element carrying id, x and y, and the loop walks it by index. The shape of the array (a column) is what jsondecode produces for an array of objects, and jsonencode reverses the conversion. In a file-based version, plate = jsondecode(fileread("plate.json")) reads the configuration, and readstruct reads JSON or XML directly (the function dates from R2020b, when it read XML; JSON support was added in R2023b) (see JSON, XML and Web Access; not run here). Both functions and jsonencode are in base MATLAB.

Structure, table or object?

Container Use when

Structure

A fixed set of named values for one record or a handful of records: configuration, options, a function’s multiple related results. Fields have different types and sizes; there is no per-column validation.

Structure array

Many records of the same shape that you loop over or gather fields from. Row filtering and grouping are manual.

Table

Tabular data with named columns of equal length, filtering, sorting, grouping and joining (Tables). struct2table converts a structure array into one.

Object (class)

Data that needs behaviour, validation of every assignment, defaults and invariants (classdef Basics). The heatflow Plate is a class for this reason.

Common errors

  • Referencing a field that does not exist. s.b where s has no field b fails with the identifier MATLAB:nonExistentField (the message says the field does not exist; exact wording varies by release, not run here). Octave 11.3.0 prints structure has no member 'b' with the identifier Octave:invalid-indexing. Guard optional fields with isfield, or use a default: if isfield(s,'b'), v = s.b; else, v = 0; end.

  • Using a list as a value. With p a 1-by-2 structure array, v = p.id receives a comma-separated list. Octave 11.3.0 assigns the first value (1) without complaint; MATLAB also keeps a single value, and the behaviour hides the mistake (not run here). Use [p.id] or p(1).id to say what you mean.

  • Concatenating structures with different fields. [a b] where a has only x and b only y fails, because a structure array needs the same field names in every element (Octave 11.3.0 printed cat: field names mismatch in concatenating structs; MATLAB raises an error with its own text, not run here).

  • The cell-value trap above, when struct('a', {...}) builds an array you did not intend.

  • Case. s.Name and s.name are different fields.

  • Assigning a field of a non-structure. If x already holds a number, x.a = 1 is an error; clear the variable or initialise with x = struct().

Where older books differ

Books for MATLAB 5 to 7 introduce structures with struct, getfield, setfield and fieldnames, and dynamic field names with the same s.(name) form. The mechanics have not changed. What is newer: jsondecode and jsonencode (R2016b) and readstruct/writestruct (see JSON, XML and Web Access for the release in which they arrived) read and write structures from files; tables (R2013b) cover record collections that older code stored as structure arrays; and the arguments block (R2019b) validates structure inputs through options.Name fields.