Unsigned Short Array to Char Array - arrays

I've seen a little bit of code that deals with unsigned short arrays and storing "strings" in them. But I am curious how one might go about converting or extracting the string out of the unsigned short array into a char array for use in printf() for debugging purposes.
unsigned short a[5];
char b[5];
a[0] = 'h';
a[1] = 'e';
a[2] = 'l';
a[3] = 'l';
a[4] = 'o';
printf("%s\n", a);
// output is just the 'h'
From my recent understanding, an unsigned short is 2 bytes so the 'h' has a Null terminator with it. Whereas typically a char is used and each character is 1 byte.
Is there a good way to extract the "string" 'hello' and put it into a char[] so it can be printed out later? Iterate over the unsigned short array and store the value into a char array?

How to convert?:
char b[6];
for(size_t i = 0; i < 5; i++) b[i] = a[i];
b[5] = 0;

Related

C strcmp - compare strings declared by char and char*

I am trying to compare 2 strings using the below code:
char a[100] = "\0";
char* b[10];
for (int i = 0; i < 10; i++)
b[i] = "";
b[0] = "xy";
a[0] = 'x';
a[1] = 'y';
int c = strcmp(a, b[0]);
I think both a and b[0] contain the string "xy", so I expect int c equal 0. However the result stored in int c is -858993460.
Why would that happen? What should I do in order to avoid this fault? Thank you very much.
Update: I found that there is some error on my computer...
char a[3] = { NULL };
char d[3] = { NULL };
a[0] = 'x';
a[1] = 'y';
a[2] = '\0';
d[0] = 'x';
d[1] = 'y';
d[2] = '\0';
int c = strcmp(a, d);
Even using this code, I got int c to be a negative value. I have no idea why that happened.
It is undefined behaviour because a is not null terminated. All string in C have to be null terminated to be used in strcmp. What strcmp does is looping over the two strings until either one of the two is NULL terminated (see Implementation of strcmp to get an idea of how it works).
You can see that if '\0' is not present anywhere you got a problem there.
Read Why do strings in C need to be null terminated? for more info:

extract a character and various short ints from the same void pointer in C

I'm trying to accomplish the following:
given the function:
int f(void *p)
take the first byte of p and extract it as a character. Then based on what that character is determine which additional bytes to extract as short ints. For example if I have a certain character c then extract byte 4 and 7 as short ints and store them in separate variables; if I have a certain different character d extract bytes 3, 4, 5 and store them as separate variables. With this information execute some other irrelevant code. I've been struggling with this for hours.
I tried the following:
int f(void *p) {
char *first = &p;
short int *third = p + 2;
short int *fifth = p + 4;
short int *seventh = p + 6;
printf("%s %s %s, %s", first, third, fifth , seventh);
}
int main(int argc, char const *argv[]) {
char test[] = "*5431234567";
f(test);
}
My result:
▒▒ϲ -1295010922 -1295010920, -1295010918
Expected:
* 4 1 3
After a while I realized I was attempting to de-reference a void pointer which does not work. So I tried casting:
char* c = (char*) p;
char first = (char) (*c)
printf("%s", first);
This gave me a seg fault.
I tried similar things with short int casting to no avail. If this is a somewhat noobish question I apologize. I'm new to C and the whole concept of pointers and references is new to me. My first language was Java which is much more forgiving.
Your input is a string, and your expected output are individual characters within the string. There is nothing short int-like about this problem.
char *s = p;
printf("%c %c %c, %c", s[0], s[2], s[4] , s[6]);
If you need to store those values into short int variables, then you do not need pointers.
short int x = s[2] - '0';
short int y = s[4] - '0';
short int z = s[6] - '0';
printf("%c %hd %hd %hd\n", s[0], x, y, z);
The characters that represent the decimal digits are guaranteed to be contiguous, so you can compute the ordinal value by calculating the offset from '0'.
char *first = &p;
Get rid of the &. You don't want the address of the p variable, you want the address stored in it, which is simply p.
char *first = p;
short int *third = p + 2;
short int *fifth = p + 4;
short int *seventh = p + 6;
printf("%s %s %s, %s", first, third, fifth, seventh);
There's no reason to be using short pointers. The elements of a string are chars, not shorts. Even when they're digits, they're still chars.
Leave them as chars, switch to %c to print them, and make sure to dereference the pointers when you do.
char *third = p + 2;
char *fifth = p + 4;
char *seventh = p + 6;
printf("%c %c %c %c\n", *first, *third, *fifth, *seventh);

Unsigned char array concatenation in C

What's the best way to concatenate unsigned char arrays in C? Furthermore, is there a way to concatenate unsigned char arrays with char arrays? 2 of these unsigned char arrays are really just strings, but for simplicity, I'm treating them as unsigned char arrays.
The requirement is complex: there is a function that will take 1 (one) unsigned char array. That one unsigned char array is really 4 variables concatenated to make up that 1 unsigned char array. To add to the complexity, the first unsigned char array is really just a string of variable length, but its max length is 60 (i.e. sometimes it would have length = 15, other times = 60).
someFunctionAssignsFirst(unsigned char *first)
{
//it could be 15 or 60 chars long.
...
}
unsigned char first[60] = //someFunctionAssignsFirst() //This is a string i.e. "variable size string max size 60"
unsigned char second[8] = "always8."; //This is a string i.e. "01234567"
unsigned char third[32] = "always32"; //This is a cryptographic key
unsigned char fourth[32] = "always32"; //This is a cryptographic key
How would I go about getting:
unsigned char allstrings[sizeof(first)+sizeof(second)+sizeof(third)+sizeof(fourth)] = //all strings combined
?
I attempted some for loops, but the variable length first is disrupting the concatenation, and I'm sure there has to be a better way.
Full Disclosure: I'm not an expert, and I don't necessarily love C. Also for the requirement, not allowed C++ or any other language.
This is what I was trying to do, and (for clarification) I don't get a null character at the end so it's not really a string.
unsigned char *first = "this is a sample string, human readable";
unsigned char *second = "12345678" //always a number
//unsigned char third -> I have the value from before and it's a key
//unsigned char fourth -> I have the value from before and it's a key
unsigned char allstrings[sizeof(first) + sizeof(second) + sizeof(third) + sizeof(fourth)];
int counter = 0;
for (int i = 0; i <= sizeof(first); i++)
{
allstrings[counter] = first[i];
counter++;
}
for (int i = 0; i <= sizeof(second); i++)
{
allstrings[counter] = second[i];
counter++;
}
for (int i = 0; i <= sizeof(third); i++)
{
allstrings[counter] = third[i];
counter++;
}
for (int i = 0; i <= sizeof(fourth); i++)
{
allstrings[counter] = fourth[i];
counter++;
}
The allstrings variable, doesn't get anything beyond "readable" in my example above.
You need to use strcpy to copy over the first part, which is a string, then use memcpy to copy over the other 3, which are not strings but char arrays.
Note that the result is not a string but a char array, i.e. it is not null terminated.
unsigned char allstrings[strlen(first)+sizeof(second)+sizeof(third)+sizeof(fourth)];
strcpy(allstrings,first);
memcpy(allstrings+strlen(first),second,sizeof(second));
memcpy(allstrings+strlen(first)+sizeof(second),third,sizeof(third));
memcpy(allstrings+strlen(first)+sizeof(second)+sizeof(third),fourth,sizeof(fourth));
I guess you want to treat the array as buffer.
So it's fine to have the declarations,
but you don't need to define the content for this moment:
unsigned char first[60];
unsigned char second[8];
unsigned char third[32];
unsigned char fourth[32];
#define ALLSTRLEN sizeof(first) + sizeof(second) + sizeof(third) + sizeof(fourth)
unsigned char allstrings[ALLSTRLEN];
The code will keep the fixed size of arrays. and please notice that the arrays should be global or static for safety reasons.
Then you can copy the contents to arrays. I just put your code under main() to concatenate these arrays:
int main()
{
strcpy((char *)first, "this is a sample string, human readable");
// do something for second, third, fourth....
//
int counter = 0;
// first array is a normal string, we have to copy null character for it
for (int i = 0; i <= strlen((char *)first)+1; i++)
{
allstrings[counter] = first[i];
counter++;
}
for (int i = 0; i <= sizeof(second); i++)
{
allstrings[counter] = second[i];
counter++;
}
for (int i = 0; i <= sizeof(third); i++)
{
allstrings[counter] = third[i];
counter++;
}
for (int i = 0; i <= sizeof(fourth); i++)
{
allstrings[counter] = fourth[i];
counter++;
}
// allstrings is finished
}
Please notice this example just works in main() function; if you call a function to concatenate four arrays, the compiler has to pass the arrays as pointers, and the sizeof() will be wrong (equal to the pointer's size).
You can test the size by doing this:
printf("sizeof(second)=%d\n", sizeof(second));

Creating an int value from multiple char array fields in C

I'm working on a C program and i am struggling with it (I've been spoiled by the concept of object orientation).
What i want to do is this:
I want to put values in a char array into an int. So for example i have char[0] == '1' and char[1] == '2'. I want to put these values in an int variable so its value is 12. I have tried looking but I am not sure how to get this done.
I really am poor at explaining so please ask for more info if necessary.
If your char array is made with characters '1' and '2':
char a[2];
a[0] = '1';
a[1] = '2';
int b = (a[0]-'0')*10 + (a[1]-'0');
If your char array is made with numbers 1 and 2:
char a[2];
a[0] = 1;
a[1] = 2;
int b = a[0] * 10 + a[1];
also, see: Why does subtracting '0' in C result in the number that the char is representing?
If the character array contains a string that is if it is zero-terminated then you can apply standard C function atoi declared in header <stdlib.h>.
For example
char s[] = "12";
int x = atoi( s );
If the array is not zero-terminated as
char s[2] = "12";
then you can convert its content to an integer manually.
For example
int x = 0;
for ( size_t i = 0; i < sizeof( s ) / sizeof( *s ); i++ )
{
x = 10 * x + s[i] - '0';
}
What you are trying to do is called parsing. In c this can be done with the atoi() function like this:
char s[] = "12";
int num = atoi(s);

C101--string vs. char:

AFunc changes what was sent to it, and the printf() outputs the changes:
void AFunc ( char *myStr, int *myNum )
{
*myStr = 's';
*myNum = 9;
}
int main ( int argc, char *argv[] )
{
char someString = 'm';
int n = 6;
AFunc(&someString, &n);
printf("%c" "%d", someString, n);
}
But what if the string was more than one char? How would the code look differently? Thanks for any help.
If it were a "string" instead of a char, you would do something like this:
#include <stdio.h>
void AFunc (char *myStr, int *myNum) {
myStr[0] = 'p'; // or replace the lot with strcpy(myStr, "pax");
myStr[1] = 'a';
myStr[2] = 'x';
myStr[3] = '\0';
*myNum = 9;
}
int main (void) {
char someString[4];
int n = 6;
AFunc(someString, &n);
printf("%s %d", someString, n);
return 0;
}
which outputs:
pax 9
A "string" in C is really an array of characters terminated by the \0 (NUL) character.
What the above code does is to pass in the address of the first character in that array and the function populates the four characters starting from there.
In C, a pointer to char isn't necessarily a string. In other words, just because you have char *x;, it doesn't mean that x is a string.
To be a string, x must point to a suitably allocated region which has a 0 in it somewhere. The data from the first character that x points to and up to the 0 is a string. Here are some examples of strings in C:
char x[5] = {0}; /* string of length 0 */
char x[] = "hello"; /* string of length 5, the array length being 6 */
char *x = "hello"; /* string of length 5. x is a pointer to a read-only buffer of 6 chars */
char *x = malloc(10);
if (x != NULL) {
strcpy(x, "hello"); /* x is now a string of length 5. x points
to 10 chars of useful memory */
}
The following are not strings:
char x[5] = "hello"; /* no terminating 0 */
char y = 1;
char *x = &y; /* no terminating 0 */
So now in your code, AFunc's first parameter, even though is a char * isn't necessarily a string. In fact, in your example, it isn't, since it only points to a memory that has one useful element, and that's not zero.
Depending upon how you want to change the string, and how the string was created, there are several options.
For example, if the myStr points to a writable memory, you could do something like this:
/* modify the data pointed to by 'data' of length 'len' */
void modify_in_place(char *data, size_t len)
{
size_t i;
for (i=0; i < len; ++i)
data[i] = 42 + i;
}
Another slightly different way would be for the function to modify data until it sees the terminating 0:
void modify_in_place2(char *data)
{
size_t i;
for (i=0; data[i]; ++i)
data[i] = 42 + i;
}
You are only dealing with chars and char pointers. None of the char pointers are valid strings as they are not null terminated.
Try defining a string and see what it looks like.
But what if the string was more than one char? How would the code look
differently? Thanks for any help
Ofcourse, you would modify the other characters as well, but in the exact same way you did the first time.
Declare a char array and pass its address
Modify values at those address
A char array would be a more clear term for a string.

Resources