I'm piddling around with an Arduino and I have next to no programming in C.
In looking through some example code I came across this array variable declaration:
byte myArray[][6] = {"0"};
I get that this is declaring an array with unspecified rows and 6 columns.
What I don't understand is the {"0"}.
Upon the execution of this like of code, what will this variable contain?
Thanks!
The expression will initialize an array that looks like this:
myArray[0][0]
^
| +----> myArray[0][1]
| |
+---+----+---+---+---+---+
myArray[0] -----> |'0'|'\0'| | | | |
+---+----+---+---+---+---+
As you don't specify the first dimension and you only initialze 1 line it defaults to byte myArray[1][6].
If you were to initialize your array with, for instance:
byte myArray[][6] = {"0", "1"};
Then it would be:
myArray[0][0]
^
| +----> myArray[0][1]
| |
+---+----+---+---+---+---+
myArray[0] -----> |'0'|'\0'| | | | |
+---+----+---+---+---+---+
myArray[1] -----> |'1'|'\0'| | | | |
+---+----+---+---+---+---+
^ |
| |
myArray[1][0] |
+--->myArray[1][1]
In this case, because you initialize 2 lines, it defaults to byte myArray[2][6].
The string literal "0" is equivalent to the compound literal (char[]){ '0', '\0' }. So the declaration is equivalent to:
byte myArray[][6] = { { '0', '\0' } };
So the resulting array will be one row that contains an ASCII 0 (or a 0 appropriate to whatever the target character set is) followed by 5 \0 or NUL bytes.
Related
This might be a bit long question. I was testing some character arrays in C and so came along this code.
char t[10];
strcpy(t, "abcd");
printf("%d\n", strlen(&t[5]));
printf("Length: %d\n", strlen(t));
Now apparently strlen(&t[5]) yields 3 while strlen(t) returns 4.
I know that string length is 4, this is obvious from inserting four characters. But why does strlen(&t[5]) return 3?
My guess is that
String: a | b | c | d | 0 | 0 | 0 | 0 | 0 | \0
Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
strlen(&t[5]) looks at the length of a string composed of positions 6, 7 and 8 (because the 10th character is a NULL terminating character, right)?
OK, then I did some experimentation and modified a code a bit.
char t[10];
strcpy(t, "abcdefghij");
printf("%d\n", strlen(&t[5]));
printf("Length: %d\n", strlen(t));
Now this time strlen(&t[5]) yields 5 while strlen(t) is 10, as expected. If I understand character arrays correctly, the state should now be
String: a | b | c | d | e | f | g | h | i | j | '\0'
Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
so why does strlen(&t[5]) return 5 this time? I've declared a character array of length 10, should then, by the same logic applied above, the result be 4?
Also shouldn't I be running into some compiler errors since the NULL terminating character is actually in the 11th spot? I'm new into C and would very much appreciate anyone's help.
First let me tell you, your "assumption"
String: a | b | c | d | 0 | 0 | 0 | 0 | 0 | \0
Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
is not correct. Based on your code, The values are only "guaranteed" up to index 4, not beyond that.
For the first case, in your code
printf("%d\n", strlen(&t[5]));
is wrong for various reasons,
you ought to use %zu for a size_t type.
&t[5] does not point to a valid string.
Any (or both) of the above causes undefined behavior and any output cannot be justified.
To elaborate, with a defintion like
char t[10];
strcpy(t, "abcd");
you have index 0 to 3 populated for t, and index 4 holds the null-terminator. The content of t[5] onward, is indeterminate.
Thus, &t[5] is not a pointer to the first element of a string, so cannot be used argument to strlen().
It may run out of bound in search of the null-terminator and experience invalid memory access and, as a side-effect, produce a segmentation fault,
It may find a null-terminator (just another garbage value) within the bound and report a "seemingly" valid length.
Both are equally likely and unlikely, really. UB is UB, there's not justifying it.
Then, for the second case, where you say
char t[10];
strcpy(t, "abcdefghij");
is once again, accessing memory out of bound.
You have all together 10 array elements to store a string, so you can have 9 other char elements, plus one null-terminator (to qualify the char array as a string).
However, you're attempting to put 10 char elements, plus a null character (in strcpy()), so you're off-by-one, accessing out of bound memory, invoking UB.
char t[10]; is not initialized so it just contains garbage values 1). strcpy(t, "abcd"); overwrites the first 5 characters with the string "abcd" and a null terminator.
However, &t[5] points at the first character after the null termination, which remains garbage. If you invoke strlen from there, anything can happen, since the pointer passed is not likely pointing at a null terminated string.
1) Garbage = indeterminate values. Assuming a sane 2's complement system, the address of the buffer t is taken, so the code does not invoke undefined behavior until the point where strlen starts reading outside the bounds of the array t. Reference.
Problem 1:
My guess is that
String: a | b | c | d | 0 | 0 | 0 | 0 | 0 | \0
Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
This assumption is wrong.
The array is not initialized to hold 0 values but contains some "random" garbage.
After copying "abcd" the upper half of the array (t[5] etc.) is still untouched resulting in a "random" length of the string due to undefined behaviour.
Problem 2:
If I understand character arrays correctly, the state should now be
String: a | b | c | d | e | f | g | h | i | j | '\0'
Position: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
Again wrong.
Your array only holds 10 characters. Theyare at index 0..9. Index 10 is out of bounds.
Your copy operation might result in this layout or it might as well just crash while writing out of bounds.
But this is not checked by the compiler. If you run into problems then it will be during runtime.
This question already has answers here:
What is the meaning of int (*pt)[5] in c [duplicate]
(3 answers)
Closed 7 years ago.
I was going through study materials from my previous year at University, and I saw a question like:
What is the difference between int *a and int a[5] and int *[5]. What does the last one indicate?
the int *a[5] declares an array of pointers to int.
the easiest was to determine the specifics of a variable declaration is read it from right to left.
In a nutshell:
int *a - creates a pointer to an int. This should contain the memory address of another int.
Example values of *a are 0x00001, 0x000057, etc.
int a[5] - creates an array that contains five int elements with each element containing an int values.
Here's a visualization of the possible values of each element in the array:
-------------------------
| Array element | Value |
-------------------------
| a[0] | 1 |
| a[1] | 2 |
| a[2] | 3 |
| a[3] | 4 |
| a[4] | 5 |
-------------------------
int *a[5] - creates an array that contains five pointer to an int elements which each element containing the memory address of another int.
Here's a visualization of the possible values of each element in the pointer array:
-------------------------
| Array element | Value |
-------------------------
| a[0] | 0x000 |
| a[1] | 0x001 |
| a[2] | 0x002 |
| a[3] | 0x003 |
| a[4] | 0x004 |
-------------------------
How are type declaration statements in C parsed (Right to Left or Left to Right)?
eg: consider the statement:
const char* const arr="hello";
How exactly is the above statement parsed?
Dear All, To those who found it difficult to understand my question:
In the above declaration statement arr is a variable. When the above statement is read by the compiler (which happens to parse the line) is arr considered a constant variable and then categorised as a character pointer or is it first recognised as a character pointer and then concluded with a constant value.
The doubt is due to the following thought:
If only const were to be declared ex: const int x; then the compiler does things behind the scene to make it a constant, and If I were to declare only a pointer ex: int* x; again compiler does things behind the scenes to categorise x as a pointer variable to distinguish it from just another integer variable. But in case the declaration is something like:
const int* const x; the behind the scenes action has to happen in some order so as x is recognised as and integer pointer variable and a const variable and then that has a constant value.
I would also be glad to hear the "behind the scenes" actions that C compiler does to separate between int variable char vaiable... pointer variable, register variable, In all how does a compiler recognise the difference.
Finally thanks for your patience to read such a long question.
Declarations aren't parsed strictly left to right or right to left. C declaration syntax is somewhat complicated.
Based on the grammar found in the online C2011 standard, section 6.7, your example parses out like so (skipping a few steps for brevity):
char const * const arr = "hello" ;
-+-- --+-- ^ --+-- -+- ^ ---+--- ^
| | | | | | | |
type type | type direct | initializer |
specifier qualifier | qualifier declarator | | |
| | | list | | | |
| | | | | | | |
| | +--+---+ | | | |
| | | | | | |
| | pointer | | | |
| | | | | | |
| | +------+------+ | | |
| | | | | |
| | declarator | | |
| | | | | |
| | +---------+----+-------+ |
| | | |
| | | |
| | | |
+---+----+ | |
| | |
declaration init-declarator-list |
specifiers | |
| | |
+-------------------------+-------+------------------------+
|
declaration
So, something to note about the pointer part of the declaration; the const following the * is part of the pointer non-terminal. That part of the grammar looks like this:
pointer:
* type-qualifier-listopt
* type-qualifier-listopt pointer
When you write T * const p, that means you are declaring p as a constant pointer; you will not be able to assign a different value to p (you can't make it point to a different object).
This also means you can declare an object like T * const * const p, or T * const restrict * volatile * p;. In each case, the list of type qualifiers is associated with the * appearing to their left.
The way to read hairy declarations is to start with the left-most identifier and work your way out, remembering the following rules:
*a[] - a is an array of pointer
(*a)[] - a is a pointer to an array
*f() - f is a function returning a pointer
(*f)() - f is a pointer to a function
* qual p - p is a qualified pointer
qual * p - p is a pointer to qualified type
where qualified may be one of const, volatile, restrict, or _Atomic. In the case of function declarations, you'll be applying these rules recursively to each function parameter.
So,
arr -- arr
* const arr -- is a const pointer to
char const * const arr -- const char
char const * const arr = "hello"; -- initialized to "hello"
This could also be written
const char * const arr = "hello";
and it will mean the same thing. The reason for this is that the declaration-specifiers non-terminal (which, in this case, covers the part of the declaration to the left of the *) is defined as
declaration-specifiers:
storage-class-specifier declaration-specifiersopt
type-specifier declaration-specifiersopt
type-qualifier declaration-specifiersopt
function-specifier declaration-specifiersopt
alignment-specifier declaration-specifiersopt
This syntax means you can have any one of a storage-class-specifier, a type-specifier, a type-qualifier, a function-specifier, or an alignment-specifier followed by zero or more additional such items (subject to certain constraints). This is how you can get declarations like
static unsigned long int x;
which parses as
static unsigned long int x ;
--+--- ----+--- --+- -+- ^ ^
| | | | | |
storage type type type direct |
class specifier specifier specifier declarator |
specifier | | | | |
| | | declaration | |
| | | specifiers | |
| | | | | |
| | +-----+----+ | |
| | | | |
| | declaration init |
| | specifiers declarator |
| | | | |
| +---------+---------+ | |
| | | |
| declaration | |
| specifiers | |
| | | |
+-----------+-------------+ init |
| declarator |
declaration-specifiers list |
| | |
+----------------------+----------------+--------+
|
declaration
The order in which static, unsigned, long, and int appear doesn't matter (although people will probably hit you if you write int long static unsigned x). Your declaration must include at least one type-specifier, and you can't write things like float char double x or double double double double y, but those rules are enforced at a different level.
In C, variables are declared the way you use them, e.g.
int * t[12];
means than *t[somevalue] is an int.
Back to your example :
const char *arr = "hello";
means you cannot change the chars inside the string
arr[0] = 'x' is forbidden
arr = "xyz" is allowed
char * const arr = "hello";
means you cannot change the value of the pointer arr
arr[0] = 'x' is allowed
arr = "xyz" is forbidden
I am learning c, and have come across an issue storing and managing structs; let me explain.
I am quite familiar with Java, and I am starting to understand how to properly use pointers and references in c. My goal is to make and store hundreds of stuct:
struct creature{
int id;
char name[12];
}
In java, I am able to create an Array like:
creature c [];
and then store and manipulate objects inside that array. I want the same effect in c using a struct "creature".
My first attempt was:
creature *creatures = malloc(sizeof(creature));
I am not entirely sure what that even does. My goal was to create a block of memory that strictly held struct pointers, like the Java array.
from here, I want to create new creature structs, and store their pointers in the creatures variable, that has memory allocated from using malloc.
I hope this was enough information to explain my problem.
Thanks!
Right, so what you want is an array of pointers. Note that in Java, whenever you have something like:
String s = ...;
This translates to a pointer in c:
String *s = ...;
Let's take the easy case first of a fixed-size array of pointers. This is simply:
creature *creatures[10];
for (var i=0; i < 10; i++) {
creatures[i] = malloc(sizeof(creature));
}
Now you have an array of pointers to creatures, each malloced separately. But, if you don't know how big your array of creatures should be, then you have to malloc the array of creatures. Note that if you have, say, a malloced int array, you'd do the following:
int *ints = malloc(sizeof(int) * 10);
ints[0]; ints[1]; //etc...
That is, an array is represented as a pointer to the first element. What you want now is an array of pointers, which ends up being a pointer to a pointer:
var numCritters = 10;
creature **creatures = malloc(sizeof(creature *) * numCritters);
for (var i=0; i < numCritters; numCritters++) {
creatures[i] = malloc(sizeof(creature));
}
The first malloc creates a pointer to an array of creature * pointers. Note we use sizeof(creature *) here, not sizeof(creature), because the array is of pointers, not of creatures.
Each of the next mallocs then creates a pointer to a creature, same as in the case of a fixed-size array.
Be sure to have a free for each malloc - that is, one for each creature * and one for the creature **.
Note that this is different from what Pankrates suggested. Which solution you want to use depends on what you want to do. His creates a big block of creatures:
creature *creatures = +--------------------+
| |
| |
| Creature 0 |
| |
| |
+--------------------+
| |
| |
| Creature 1 |
| |
| |
+--------------------+
| |
| |
| Creature 2 |
| |
| |
+--------------------+
| ... |
Whereas mine creates an array of pointers, each one pointing to a creature:
+--------------------+
| |
creature *creatures = +------+ | |
| ptr0 | ----> | Creature 0 |
+--------------------+ +------+ | |
| | +-- | ptr1 | | |
| | | +------+ +--------------------+
| Creature 1 | <-+ | ptr2 | --+
| | +------+ | +--------------------+
| | | .... | | | |
+--------------------+ | | |
+-> | Creature 2 |
| |
| |
+--------------------+
You are almost there. malloc takes the number of bytes that you want to allocate as an argument, therefore you need to multiply the size of the struct times the number of structs that you want to allocate:
int number_of_creatures = 10;
creature *creatures = malloc(sizeof(creature) * number_of_creatures);
You should also always check the returned pointer from malloc() to check if the allocation was successful
if (creatures == NULL)
printf("Allocating memory failed!\n");
i am trying to cast a void** pointer to an int** 2D array in C
here is the code that i am trying to work with (with all the extraneous bits removed):
\*assume that i have a data structure called graph with some
*element "void** graph" in it and some element "int order" */
void initialise_graph_data(graph_t *graph)
{
void **graph_data = NULL;
int (*matrix)[graph->order];
size_t size = (graph->order * graph->order) * sizeof(int);
graph_data = safe_malloc(size); /*safe malloc works fine*/
matrix = (int(*)[graph->order])graph_data;
graph->graph = graph_data;
}
when i compile that, it works fine, but gives me a warning that variable 'matrix' is set but not used. i dont really want to have to use the interim matrix variable because the function is just supposed to initialise the array, not put anything in it; but if i try to cast graph_data directly to an int** when i am assiging it to graph->graph like so:
graph->graph = (int(*)[graph->order])graph_data;
it gives me an assignment from incompatible pointer type warning.
am i just not casting it properly? does anyone have any suggestions as to how i can make it work without the interim "matrix" variable? or if not, what i can do with that variable so that it doesnt give me the warning that it is set but not used?
thanks
The compiler is right, an array of arrays (or a pointer to an array) is not the same as a pointer to a pointer. Just think about how they would be laid out in memory:
A matrix of size MxN in the form of an array of arrays:
+--------------+--------------+-----+----------------+--------------+-----+------------------+
| matrix[0][0] | matrix[0][1] | ... | matrix[0][N-1] | matrix[1][0] | ... | matrix[M-1][N-1] |
+--------------+--------------+-----+----------------+--------------+-----+------------------+
A and the same "matrix" in the form of pointer to pointer:
+-----------+-----------+-----------+-----+
| matrix[0] | matrix[1] | matrix[2] | ... |
+-----------+-----------+-----------+-----+
| | |
| | V
| | +--------------+--------------+-----+
| | | matrix[2][0] | matrix[2][1] | ... |
| | +--------------+--------------+-----+
| |
| V
| +--------------+--------------+-----+
| | matrix[1][0] | matrix[1][1] | ... |
| +--------------+--------------+-----+
|
V
+--------------+--------------+-----+
| matrix[0][0] | matrix[0][1] | ... |
+--------------+--------------+-----+
It doesn't matter if you allocate the correct size, the two variables simply are incompatible which is what your compiler is telling you.