Input element into char array using a variable - c

I need to input an element into a static const char []. I've tried with snprintf, strcat but it not working on my case because char array contains some NULL characters.
char SBP_BASE_LAT[] = "surveyed_position""\x00""surveyed_lat""\x00";
I have variable position_lati of type float and I want to input it into SBP_BASE_LAT, like
float position_lati = 43.456745;
char SBP_BASE_LAT[] = "surveyed_position""\x00""surveyed_lat""\x00"["%f",position_lati];
What is the solution?
Thanks;

This declaration you presented ...
char SBP_BASE_LAT[] = "surveyed_position""\x00""surveyed_lat""\x00";
... declares SBP_BASE_LAT as an array of char, with size derived from its initializer -- 32, including the additional terminator, if I have counted correctly. The array elements are not const.
It is legal to include null bytes in the array's initializer as you do, but the usefulness of doing so seems doubtful. All standard functions that handle strings will interpret the first embedded null byte as a string terminator, and if that's what you intend then it's unclear why you present a longer initializer.
I have variable position_lati of type float and I want to input it into SBP_BASE_LAT [...]
You cannot do this via an initializer, because initializers must be compile-time constants. You could do it at runtime like so:
float position_lati = 43.456745;
/* plenty of extra space to append the formatted value: */
char SBP_BASE_LAT[50] = "surveyed_position""\x00""surveyed_lat""\x00";
int base_lat_end;
/*
* compute the combined length of the first two zero-terminated
* segments of SBP_BASE_LAT
*/
base_lat_len = strlen(SBP_BASE_LAT) + 1;
base_lat_len += strlen(SBP_BASE_LAT + base_lat_len) + 1;
/*
* Format the value of position_lati into the tail of
* SBP_BASE_LAT, following the second embedded zero byte.
*/
sprintf(SBP_BASE_LAT + base_lat_len, "%9.6f", position_lati);
Of course, that all supposes that the value of position_lati is not known until run time. If it is known at compile time then you can just put that value literally into the array initializer.
Also, if your array were actually const, then you could not modify its contents after intialization, so a sprintf()-based approach such as I describe would not work.

Related

C : If as I understand 0 and '\0' are the same, how does the compiler knows the size of an array when I write int my_array = {0};?

I am trying to create a function to copy an array into another using pointers. I'd like to add the following condition : if the array of destination is smaller, the loop must break.
So basically it's working, but it is not working if I intilize the the destination array as follows :
int dest_array[10] = {0};
From what I understand it fills the array with int 0's which are equivalent to '\0' (null characters). So here is my question :
In this case how can the computer know the array size or when it ends ?
(And how do I compare arrays passed as parameters ?)
void copy(int *src_arr, int *dest_arr)
{
// The advantage of using pointers is that you don't need to provide the source array's size
// I can't use sizeof to compare the sizes of the arrays because it does not work on parameters.
// It returns the size of the pointer to the array and not of of the whole array
int* ptr1;
int* ptr2;
for( ptr1 = source, ptr2 = dest_arr ;
*ptr1 != '\0' ;
ptr1++, ptr2++ )
{
if(!*ptr2) // Problem here if dest_arr full of 0's
{
printf("Copy interrupted :\n" +
"Destination array is too small");
break;
}
*ptr2 = *ptr1;
}
In C, it is impossible to know the length of an array inherently. This is due to the fact that an array is really just a contiguous chunk of memory, and the value passed to functions is really just a pointer to the first element in the array. As a result of this, to actually know the length of an array within a function other than the function where that array was declared, you have to somehow provide that value to the function. Two common approaches are the use of sentinel values which indicate the last element (similar to the way '\0', the null character, is per convention interpreted as the first character not part of a string in C), or providing another parameter which contains the array length.
As a very common example of this: if you have written any programs which use command-line parameters, then surely you are familiar with the common definition of int main(int argc, char *argv[]), which uses the second of the aforementioned approaches by providing the length of the argv array via the argc parameter.
The compiler has some ways to work around this for local variables. E.g., the following would work:
#include <stdio.h>
int main(){
int nums[10] = {0};
printf("%zu\n", sizeof(nums)/sizeof(nums[0]));
return 0;
}
Which prints 10 to STDOUT; however, this only works because the sizeof operation is done locally, and the compiler knows the length of the array at that point.
On the other hand, we can consider the situation of passing the array to another function:
#include <stdio.h>
int tryToGetSizeOf(int arr[]){
printf("%zu", sizeof(arr)/sizeof(arr[0]));
}
int main(){
int nums[10] = {0};
printf("%zu\n", sizeof(nums)/sizeof(nums[0]));
puts("Calling other function...");
tryToGetSizeOf(nums);
return 0;
}
This will end up printing the following to STDOUT:
10
Calling other function...
2
This may not be the value you're expecting, but this occurs due to the fact that the method signature int tryToGetSizeOf(int arr[]) is functionally equivalent to int tryToGetSizeOf(int *arr). Therefore, you are dividing the size of an integer pointer (int *) by the size of a single int; whereas while you're still in the local context of main() (i.e., where the array was defined originally), you are dividing the size of the allocated memory region by the size of the datatype that memory region is partitioned as (int).
An example of this available on Ideone.
int* ptr1;
int* ptr2;
You lose size information when you refer to arrays as pointers. There is no way you can identify the size of the array i.e. the number of elements using ptr1. You have to take help of another variable which will denote the size of the array referred by ptr1 (or ptr2).
Same holds for character arrays as well. Consider the below:
char some_string[100];
strcpy(some_string, "hello");
The approach you mentioned of checking for \0 (or 0) gives you the number of elements which are part of the string residing in some_string. In no way does it refer to the number of elements in some_string which is 100.
To identify the size of destination, you have to pass another argument depicting its size.
There are other ways to identify the end of the array but t is cleaner to pass the size explicitly rather than using some pointer hack like passing a pointer to end of the array or using some invalid value as the last element in array.
TL/DR - You will need to pass the array size as a separate parameter to your function. Sentinel values like 0 only mark the logical end of a sequence, not the end of the array itself.
Unless it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array. So when you pass your source and destination arrays as arguments to copy, what the function actually receives is just two pointers.
There's no metadata associated with a pointer that tells it whether it's pointing to the first object in a sequence, or how long that sequence is1. A sentinel value like the 0 terminator in strings only tells you how long a logical sequence of values is, not the size of the array in which they are stored2.
You will need to supply at least one more parameter to copy to tell it how large the target buffer is, so you stop copying when you've reached the end of the target buffer or you see a 0 in the source buffer, whichever comes first.
The same is true for array objects - there's no runtime metadata in the array object to store the size or anything else. The only reason the sizeof trick works is that the array's declaration is in scope. The array object itself doesn't know how big it is.
This is a problem for library functions like strcpy, which only receives the starting address for each buffer - if there are more characters in the source buffer than the target is sized to hold, strcpy will blast right past the end of the target buffer and overwrite whatever follows.

String array initialization in C

In C it's possible to initialize a string array with such line of code:
char *exStr[] = { "Zorro", "Alex", "Celine", "Bill", "Forest", "Dexter" };
On my debugger the array is initialized as below:
This is different as standard two-dimensional array where each string occupy the same amount of byte; can someone point me on the right direction to understand:
What's means exactly the declaration "char *exStr[] = ...";
How can I re-create the same variable's structure from my program.
What's means exactly the declaration "char *exStr[] = ...";
It means 'array of poniter to char'. Char data of literals like "Zorro" are usually placed in read-only data segments, and array elements inlcude only address of the first char of literal.
How can I re-create the same variable's structure from my program.
You can do something like:
char zorro[] = {'Z', 'o', 'r', 'r', 'o', '\0'}; // initialized every char for clarity
char alex[] = "Alex";
char celine[] = "Celine";
...
char* exStr[] = {
&zorro[0], // explicitly referenced for clarity
alex,
celine,
...
};
1.
As the other answers and comments said, the expression "char *exStr[]" means "array of pointers to char".
a) How to read it
The best way to read it (as well as other more complex C declarations) is to start at the thing's name (in this case "exStr") and work your way towards the extremities of the declaration, like this:
First go right, adding each encountered meaningful symbol(s) to the meaning of the expression
Stop going right at the first closing paranthesis ")", or when the expression ends
When you cannot go right anymore, resume where you started and go left, again adding each encountered symbol to the meaning of the expression
Stop going left at the paranthesis "(" that corresponds to the ")" that stopped you on the right, or at the beginning of the expression
When stopped going left at a "(" paranthethis and you haven't reached the beginning of the expression, resume going right immediately after the ")" that corresponds to it
Keep going right and left until you reach the margins of the expression both ways
In your case, you would go like that:
start at exStr: that's the variable's name
go right: []: exStr is an array
go right: stop: there's nothing there, the "=" sign stops us
go left: *: exStr is an array of pointers
go left: char: exStr is an array of pointers to char
go left: stop: there's nothing there, the "=" sign stops us
b) Why are you seeing that each array element occupies a different amount of bytes
When you have a value like "Zorro", it's a C string.
A C string is an array of bytes that starts at a given address in memory and ends with 0. In case of "Zorro" it will occupy 6 bytes: 5 for the string, the 6th for the 0.
You have several ways of creating C strings. A few common ones are:
A) use it literally, such as:
printf("Zorro");
B) use it literraly but store it in a variable:
char *x = "Zorro";
C) allocate it dynamically and copy data into it
size_t n = 2;
char *p = malloc((n+1) * sizeof(char));
char c = getch(); // read a character from the console
p[0] = c;
p[1] = 0;
// do something with p...
free(p);
Whenever you're putting a string value like "Zorro" in your program, the compiler will reserve memory for just enough to hold this string plus the 0 terminator. It will initialize this memory with whatever you provided inside "", it will add the 0, and secretly keep a pointer to that memory. It will prevent you from modifying that memory (you cannot change that string).
In your code sample, it did this for every string that appeared in the exStr initialization.
That's why you see each array element occupying a different amount of memory. If you look closer to your debugger output, you'll see that the compiler reserved memory for a string immediately after the preceding one, and each string occupies its length in bytes plus the 0 terminator. E.g. "Zorro" starts at 02f, and occupies positions 02f - 034, which are 6 bytes (5 for Zorro and 1 for the 0 terminator). Then "Alex" starts at 035, occupies 5 bytes: 035 - 039, and so on.
2.
To create a similar array programmatically:
If all you have are some static strings like in your example, then your code sample is good enough.
Otherwise if you plan to put dynamic values into your array (or if you plan to change the original strings in the program), you would do something like:
#define COUNT 5
char *strings[COUNT];
int i;
for (i = 0; i < COUNT; i++) {
int n = 32; // or some other suitable maximum value, or even a computed value
strings[i] = malloc((n+1) * sizeof(char));
// put up to 32 arbitrary characters into strings[i], e.g. read from a file or from console; don't forget to add the 0 terminator
}
// use strings...
// free memory for the strings when done
for (i = 0; i < COUNT; i++) {
free(strings[i]);
}
What's means exactly the declaration "char *exStr[] = {......};
Here, exStr is an array of char pointers, initialized by the supplied brace enclosed initializers.
To elaborate, the starting address of each string literal in the initializer list is stored into each element of the array.
Point to note, the contents of the array elements (being string literals) are not modifiable.
Regarding the second part,
How can I re-create the same variable's structure from my program.
is not clear. Can you elaborate on that part?
Just in case, if you meant how to access, then, it's just like the normal array access. As long as you're within bounds, you're good to go.
For the second part of your question, I guess you are asking for an array of pointers to variable length strings.
It can be done like this:
#include <stdio.h>
int main(void) {
char* ma[2]; // Array of char pointers for pointing to char-strings
char* pZorro = "Zorro"; // Char string - not modifiable
char AlexString[5] = {"Alex"}; // Char string - modifiable
ma[0] = pZorro; // Make the first pointer point to the "Zorro" string
ma[1] = AlexString; // Make the second pointer point to the "Alex" string
printf("%s\n", ma[0]);
printf("%s\n", ma[1]);
// strcpy(ma[0], "x"); // Run time error! Can't change "Zorro"
strcpy(ma[1], "x"); // OK to change "Alex"
printf("%s\n", ma[0]);
printf("%s\n", ma[1]);
return 0;
}
The output will be:
Zorro
Alex
Zorro
x

Google Protobuf-c repeated strings

My Google protobuf-c proto file looks like this:
message foo{
required uint32 addresscount= 1;
repeated string destination_hops= 2;
}
I want an array of strings and addresscount is supposed to give the count of array elements.
The generated protobuf-h file is
struct _foo
{
ProtobufCMessage base;
uint32_t addresscount;
size_t n_destination_hops;
char **destination_hops;
};
I assume that n_destination_hops is the number of times the string destination_hops appears in the message. I had kept addresscount for that purpose and i guess thats not required. My question is this:
char **destination_hops is a pointer to an array of char * pointers. Each index can be of different length. How will protobuf know the size of each char * pointer when it has packed this into a stream. Does protobuf assume that all destination_hops would be of the same size and is that given by size_t n_destination_hops?
DOUBT 2:
char ** destination_hops is an array of char * pointers.
This means i can look at it as char *destination_hops[0], char *destination_hops[1], etc
If this is correct then shouldn't i be able to set char *destination_hops[0] = "abc".
When i do that i get a segmentation fault.
Any idea why?
I assume that n_destination_hops is the number of times the string destination_hops appears in the message.
Yep.
I had kept addresscount for that purpose and i guess thats not required.
Right.
char **destination_hops is a pointer to an array of char * pointers. Each index can be of different length. How will protobuf know the size of each char * pointer when it has packed this into a stream.
In the wire representation of the string, it is preceded by the string's length, coded as a packed integer. In memory, they are just ordinary zero-terminated C strings, so:
NUL is not a valid character in the string
the length can be computed with strlen
Protobuf requires that the value of a string be a sequence of UTF-8 encoded characters. If you want to include NUL or bytes which are not part of a valid UTF-8 sequence, use bytes instead of string. If you do that, the in-memory datastructure will include an explicit length.
Shouldn't i be able to set char *destination_hops[0] = "abc"
I suppose you mean that you should be able to write:
destination_hops[0] = "abc";
That's valid C, but it requires that destination_hops have at least one element. A newly initialized foo will have n_destination_hops = 0; and destination_hops = NULL;, in which case trying to access destination_hops[0] will try to dereference NULL, which is a segfault. (Or UB, if you prefer.9

Convert struct field to unsigned char string

I'm on an embedded system so do not have access to a most of the standard library. I have a struct which contains char values.
I have a simple print function which simply outputs an unsigned char string to an attached screen. It does not support format specifiers like printf does.
This is the struct:
typedef struct my_options{
char test;
} my_options;
And this is where I'm trying to output the value:
struct my_options options;
print(options.test); //Here I get "implicit conversion of int to ptr"
How do I achieve this?
Create a char array to hold your char and then print it:
char wrapper[2];
wrapper[0] = options.test;
wrapper[1] = '\0';
print(wrapper);
Create a temporary 2-character long string that has the character to print, and then the terminator. Then pass that string to your print() function:
void print_options(const struct my_options *opt)
{
char tmp[] = { opt->test, '\0' };
print(tmp);
}
your member test if of the type char, where the print function expects an argument of the type const char * (assuming the const bit here, but that's what I'd expect, this as an asside). Passing the address of test then would seem like the appropriate solution, but is it?
No, of course it isn't. There is no absolute guarantee that the next byte after test will be '\0' (a string terminating char). What you, then, ought to do is create a wrapper string:
char char_wrapper[2] = {};//initializes according to standard
//but as Lundin pointed out, self-documenting code is important:
char_wrapper[0] = options.test;?
char_wrapper[1] = '\0';//explicit, so it's clear what this code does
print(char_wrapper);
That should work just fine.
You can, of course, write this as a one-liner:
char char_wrapper[2] = {options.test, '\0'};//same as before, only in 1 statement
print(char_wrapper);//print "string"
That should do it, really. You don't even have to explicitly write the terminating char, since the standard specifically states:
An array of character type may be initialized by a character string literal, optionally
enclosed in braces. Successive characters of the character string literal (including the
terminating null character if there is room or if the array is of unknown size) initialize the
elements of the array.
6.7.8 Initialization cf p. 138, semantics, point 14
Be that as it may, I'd still prefer to browse the web, or just set about writing your own minor implementation of printf so you can use format specifiers. Heck, it's one of the first exercises in the K&R book, and there's tons of solutions floating about on the net. check those out, and adapt them to your specific needs.
Or, perhaps define print to accept a size_t argument, to specify how many chars you want to pass to the output stream. and call it like so print(options.test, 1);
print is looking for a char*. You are passing an char which can also be represented as an int. Thus, the function is trying to implicitly convert an int to a pointer as it is telling you.
char ptr[2];
ptr[0] = options.test;
ptr[1] = '\0';
Would wrap the char into a char array, which in C will decay into a pointer when you pass it to a function.

How can this char array store four separate strings?

I'm confused by this snippet from the book I'm reading. Text strings are put into a char array. There are four words, with four elements in the array. Wait, but that means a single char element is containing a whole text string. I'm certain chars can only handle a single character. Here's the code.
const char *words[4] = { "aardvark", "abacus",
"allude", "zygote" };
So what gives? How can the author be using chars to store whole strings? I know the solution must be blindingly obvious, but I just can't see it. Also, what's with the const keyword? Why would it need to be read only if all we plan to do with this array is count the length of each word using strlen()?
The code does not use chars to store strings, note that the declaration is an array of char *.
A char can hold a single character, and a char * can be used to point to the first element of an array of characters, which can hold a standard C string. This is an important C fundamental: see a char * and you should immediately think of null-terminated C strings.
Similarly, an int * can be used to refer to an entire array of int, by holding the address of the first int in the array. int* can be subscripted the same as an array declared using [].
A char * can also be used to simply hold the address of a single character - i.e. not the first character in a null terminated string.
How can the author be using chars to store whole strings?
he can't. You notice the asterisk, right?
The point your missing is the *.
char letter = 'a'; //stores a single character
char *word = "bigger"; //stores a string literal
this means word is really:
word ---> [b][i][g][g][e][r][\0]
pointing to a bunch of chars (or a "string" of chars). In your example the author defined:
const char *words[4] = { "aardvark", "abacus", "allude", "zygote" };
So you have 4 strings of chars, which are constant. The const was the author's choice to add that on there... it could have been left off. It's just a safeguard, a note to the compiler (and author) that these values were not ment to be modified.

Resources