Unsigned char array concatenation in C - 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));

Related

Compress string using bit field

I have to encode an array of strings such that: 1. The encoded output is a single string with minimum possible length 2. You should be able to decode the string later.
String is made up of only lower case characters. I am not very good in using bit fields.
. Do i just right shift by 3 when I am assign the letter to enc_string. Or I can use the structure I created? Also how can I make sure that I actually saved space. I cant use sizeof as it returns in bytes?
How do I do the bit packing.
#include <stdio.h>
typedef struct{
int val:5;
}input;
char* encode_string(char **str_arr,int len, int *ret_len){
int i = 0;
int j = 0;
int k = 0;
char *enc_string = (char*)malloc(10*len*sizeof(char));
for(i=0;i<len;i++){
for(j=0;j<strlen(str_arr[i]); j++){
enc_string[k] = str_arr[i][j]; // str_arr[i][j]>>3
k++;
}
enc_string[k++] = '*';
}
if(k>0){
enc_string[k]='\0';
*ret_len = k;
}
return enc_string;
}
int main()
{
char* str[] = {"abcd","fghi","jkl"};
char *enc_string;
int enc_len = 0;
enc_string = encode_string(str,3,&enc_len);
printf("Encoded string %s size %d \n",enc_string,enc_len);
return 0;
}

Increment Char Array Pointer

Is it possible to increment/advance a char array like I can a char pointer?
For example I can do this for a char pointer:
while (*cPtr)
printf("c=%c\n", *(cPtr++));
But I am not able to do this:
// char cArray[] = "abcde";
while (*cArray)
printf("c=%c\n", *(cArray++)); // Compile error: 19 26 [Error] lvalue required as increment operand
The purpose is to be able to iterate over a char array when I dont know the length of the array. My thinking is that I just want to advance till I find a null character I guess unless theres an easier way?
char a[] = "abcde";
int index = -1;
while (a[++index])
printf("c=%c\n", a[index]);
Is it possible to increment/advance a char array like I can a char pointer?
Unlike pointers, arrays are not lvalues and you can't modify it. That's a major difference between arrays and pointers.
Do something like that:
char cArray[] = "abc def";
char *p = &cArray[0];
while (*p)
printf("c=%c\n", *(p++));
You can do:
for(int i = 0; i < 5; i++) // if you know the length
printf("c=%c\n", a[i]);
or get the size with sizeof() and replace i < 5 with i < size:
int size = (sizeof(a) / sizeof(*a))
I have used this with success under keil uVision:
char buffer[512];
uint8_t var[512]; // uint8_t = integer 8bit
for(int i = 0; i < 128; i = i + 4)
sprintf(&buffer[i],"%03d,", var[y]); //this will put 4 bytes in buffer
Better way to do this:
char buffer[128];
uint8_t int_buffer[24]; // gets updated in an interrupt - some sensors values
uint8_t i = 0;
uint8_t PrintSize = 0;
while(/*myFile is smaller than 1Mb..*/)
{
PrintSize = 0;
i = 0;
while(i < 23)
{
PrintSize += sprintf(buffer + PrintSize,"%01d,",int_buffer[i]);
i++;
}
PrintSize += sprintf(buffer + PrintSize,"%01d\n", int_buffer[23]);
//write buffer to a file in my app
}
File content is like this:
41,1,210,243,120,0,210,202,170,0,14,28,0,0,0,1,85,0,5,45,0,0,0,1
40,1,215,255,119,0,215,255,170,0,14,37,0,0,0,1,85,0,5,46,0,0,0,1

How to fill a string with random (hex) characters?

I have a string (unsigned char) and i want to fill it with only hex characters.
my code is
unsigned char str[STR_LEN] = {0};
for(i = 0;i<STR_LEN;i++) {
sprintf(str[i],"%x",rand()%16);
}
Of course, when running this I get segfaulted
string is an array of char-s not unsigned char-s
you are using str[i] (which is of type unsigned char) as a 1st argument to sprintf, but it requires type char * (pointer).
This should be a little better:
char str[STR_LEN + 1];
for(i = 0; i < STR_LEN; i++) {
sprintf(str + i, "%x", rand() % 16);
}
The first argument to sprintf() should be a char*, but str[i] is a char: this is the cause of the segmentation fault. The compiler should have emitted a warning about this. gcc main.c, without specifying a high warning level, emitted the following:
warning: passing argument 1 of sprintf makes pointer from integer without a cast
A hex representation of a character can be 1 or 2 characters (9 or AB for example). For formatting, set the precision to 2 and the fill character to 0. Also need to add one character for the terminating null to str and set the step of the for loop to 2 instead of 1 (to prevent overwriting previous value):
unsigned char str[STR_LEN + 1] = {0};
int i;
for (i = 0; i < STR_LEN; i += 2)
{
sprintf(&str[i], "%02X", rand() % 16);
}
You could try something like this:
#include <stdio.h>
#include <stdlib.h>
#define STR_LEN 20
int main(void)
{
unsigned char str[STR_LEN + 1] = {0};
const char *hex_digits = "0123456789ABCDEF";
int i;
for( i = 0 ; i < STR_LEN; i++ ) {
str[i] = hex_digits[ ( rand() % 16 ) ];
}
printf( "%s\n", str );
return 0;
}
There are several unclarities and problems in your code. I interpret "hex character" to mean "hex digit", i.e. a symbol from {0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f}, not "the hexadecimal value of an ascii character's code point". This might or might not be what you meant.
This should do it:
void hex_fill(char *buf, size_t max)
{
static const char hexdigit[16] = "0123456789abcdef";
if(max < 1)
return;
--max;
for(i = 0; i < max; ++i)
buf[i] = hexdigit[rand() % sizeof hexdigit];
buf[max] = '\0';
}
The above will always 0-terminate the string, so there's no requirement that you do so in advance. It will properly handle all buffer sizes.
My variation on some of answers below; note the time seeded rand function and instead of a char using a const size, I use a vector that is then converted to a string array.
Boost variate generator docs
std::string GetRandomHexString(unsigned int count)
{
std::vector<char> charVect = std::vector<char>(count);
//Rand generator
typedef boost::random::mt19937 RNGType;
RNGType rng(std::time(nullptr) + (unsigned int)clock());
//seeding rng
uniform_int<> range(0, 15); //Setting min max
boost::variate_generator<RNGType, boost::uniform_int<> >generate(rng, range); //Creating our generator
//Explicit chars to sample from
const char hexChars[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
//
for (int i = 0; i < count; i++)
{
charVect[i] = hexChars[generate()];
}
//
return std::string(charVect.begin(), charVect.end());;
}
Examples (count = 32):
1B62C49C416A623398B89A55EBD3E9AC
26CFD2D1C14B9F475BF99E4D537E2283
B8709C1E87F673957927A7F752D0B82A
DFED20E9C957C4EEBF4661E7F7A58460
4F86A631AE5A05467BA416C4854609F8

C Library function for converting a string of hex digits to ints?

I have a variable length string where each character represents a hex digit. I could iterate through the characters and use a case statement to convert it to hex but I feel like there has to be a standard library function that will handle this. Is there any such thing?
Example of what I want to do. "17bf59c" -> int intarray[7] = { 1, 7, 0xb, 0xf, 5, 9, 0xc}
No, there's no such function, probably because (and now I'm guessing, I'm not a C standard library architect by a long stretch) it's something that's quite easy to put together from existing functions. Here's one way of doing it decently:
int * string_to_int_array(const char *string, size_t length)
{
int *out = malloc(length * sizeof *out);
if(out != NULL)
{
size_t i;
for(i = 0; i < length; i++)
{
const char here = tolower(string[i]);
out[i] = (here <= '9') ? (here - '\0') : (10 + (here - 'a'));
}
}
return out;
}
Note: the above is untested.
Also note things that maybe aren't obvious, but still subtly important (in my opinion):
Use const for pointer arguments that are treated as "read only" by the function.
Don't repeat the type that out is pointing at, use sizeof *out.
Don't cast the return value of malloc() in C.
Check that malloc() succeeded before using the memory.
Don't hard-code ASCII values, use character constants.
The above still assumes an encoding where 'a'..'f' are contigous, and would likely break on e.g. EBCDIC. You get what you pay for, sometimes. :)
using strtol
void to_int_array (int *dst, const char *hexs)
{
char buf[2] = {0};
char c;
while ((c = *hexs++)) {
buf[0] = c;
*dst++ = strtol(buf,NULL,16);
}
}
Here's another version that allows you to pass in the output array. Most of the time, you don't need to malloc, and that's expensive. A stack variable is typically fine, and you know the output is never going to be bigger than your input. You can still pass in an allocated array, if it's too big, or you need to pass it back up.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
/* str of length len is parsed to individual ints into output
* length of output needs to be at least len.
* returns number of parsed elements. Maybe shorter if there
* are invalid characters in str.
*/
int string_to_array(const char *str, int *output)
{
int *out = output;
for (; *str; str++) {
if (isxdigit(*str & 0xff)) {
char ch = tolower(*str & 0xff);
*out++ = (ch >= 'a' && ch <= 'z') ? ch - 'a' + 10 : ch - '0';
}
}
return out - output;
}
int main(void)
{
int values[10];
int len = string_to_array("17bzzf59c", values);
int i = 0;
for (i = 0; i < len; i++)
printf("%x ", values[i]);
printf("\n");
return EXIT_SUCCESS;
}
#include <stdio.h>
int main(){
char data[] = "17bf59c";
const int len = sizeof(data)/sizeof(char)-1;
int i,value[sizeof(data)/sizeof(char)-1];
for(i=0;i<len;++i)
sscanf(data+i, "%1x",value + i);
for(i=0;i<len;++i)
printf("0x%x\n", value[i]);
return 0;
}

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