A Cicada string is a ‘list’ of characters, the list being a special datatype roughly analogous to an array. Therefore we can read a string into C the same way we read in a character array, e.g. using the arrayRef() macro, as in the examples above. This method lets us both read and modify the characters in the string, since the characters were passed into C by reference. However, it does not allow us to resize the string.
In order to pass a string (or other list) that our C function can resize, we have have to instruct Cicada to pass more information about the string than just the pointer to its first character. This is done in the C function declaration passed to Cicada; for example:
const Cfunction fs[] = { { "myFunction:dadd", &myFunction } };
The argument styles are specified after the Cicada function name: ‘d’ to pass argument data, and ‘a’ to pass a resizable argument. ‘d’ is the default when argument styles are not specified.
Inside the C code, a resizable argument is represented by an arg pointer, and requires special functions to access. Here is how we might modify our example to convert the string to a C-style string with a null terminator.
...
arg *secondArg;
char *secondArgChars;
ccInt numChars;
...
getArgs(args, byValue(&firstArg), &secondArg, &thirdArg, &fourthArg);
numChars = 1;
stepArg(secondArg, 1, &numChars);
setStringSize(secondArg, 1, numChars+1, &secondArgChars);
secondArgChars[numChars] = 0;
We could have also written setMemberTop() instead of setStringSize() -- same arguments, identical functions, only a little bit clearer to write one or the other depending on context.
The other two functions that act on args-type variables are getArgTop() for obtaining the number of indices spanned by an argument, and argData() for getting the data pointer. For example, we could also obtain secondArgChars by writing
secondArgChars = argData(secondArg);
as long as we call this function after resizing secondArg (because the pointer will change).
When we pass a whole argument we obtain an object that may have a more complex type than one or more bool, char, int, or double variables. In the example above the argument was a list of characters, i.e. a list variable pointing to a character variable. We can check these more elaborate datatypes in several ways:
bool passedCheck = false;
if (args.type[1][0] == list_type) passedCheck = (args.type[1][1] == char_type);
if (!passedCheck) return type_mismatch_err;
or
errCode = getArgs(args, fromArg(1), scalarRef(listOf(char_type), &secondArg), endArgs);
or
errCode = getArgs(args, fromArg(1), scalarRef(string_type, &secondArg), endArgs);
since string_type is shorthand for a list of characters.
There is also a corresponding array_type and an arrayOf() macro for type-checking. Although multidimensional arrays become effectively one-dimensional arrays when passing arguments as data, that is not true when a resizable argument is passed, so if we were to pass the fourth argument as an arg pointer its desired type would be arrayOf(arrayOf(double_type)).
Last update: November 12, 2025