Using char* to store data and error produced - c++

const char* val1 = advertisedDevice.getAddress().toString().c_str();
Serial.printf("Advertised Device: %s \n", val1);
This code is used to retrieve the MAC address of a BLE device.
The output of val1 on the serial monitor is:
Advertised Device: 45:89:a2:d8:74:65
But when I try to output val1 individually the system crashes. The code is shown below. Why is this?
Serial.printf("Val is : %s", val1[0]);
I should expect the serial monitor is print out
Val is : 4
I am also trying to store val1 is a string array, so for example
pseudo-code
String arr[50];
loop{
const char* val1 = advertisedDevice.getAddress().toString().c_str();
Serial.printf("Advertised Device: %s \n", val1);
arr[i] = val1[0]+val1[1]+val1[2]+....+val1[18]
i++;
}
I want to store it in a single array because I then upload it to a database. I cant do this if its in the form of val1[0],val1[1]... and so on. It will be easier to store all the data in a single array location i.e.
arr[1] = "45:47:89:fd:12",
arr[2] = "47:AC:1b:24:58" and so on.
Is this right?

Serial.printf("Val is : %s", val1[0]);
%s expects a string of characters, i.e. a char * or const char * variable. val1 is a const char *, so val1[0] is a char that is the first character within val1. You need to change %s to %c, or else Serial.printf will believe the value of val1[0] is an address to a string of characters, causing a crash or undefined behavior.
If you meant for val1 to be an array of strings, you need to declare it as that. For example:
const char *val1[50];
val1[0] = advertisedDevice.getAddress().toString().c_str();
Serial.printf("Val is : %s", val1[0]); // Now this will work
Edit: If you're looking to build a list of strings out of arr, you should be able to simply assign to arr and access the strings through it:
String arr[50];
loop{
arr[i] = advertisedDevice.getAddress().toString().c_str();
// If above doesn't work, try: arr[i] = String(...);
Serial.printf("Advertised Device: %s \n", arr[i]);
i++;
}

Related

How to send data as input with IOConnectCallStructMethod

I'm trying to use IOConnectCallStructMethod so send data in the input field to talk to my driver in DriverKit (iPadOS)
In this particular method I send an input and I expect getting an output. But ignore the output for now.
In my case IOConnectCallStructMethod is called with Swift:
var input:[UInt8] = Array(repeating: 0, count: 200)
for i in 0..<200 {
if (i % 2 == 0) {
input[i] = UInt8(i)
}
}
let arraySize:Int = input.count;
var outputSize = MemoryLayout<UInt8>.size * arraySize
var output:[UInt8] = Array(repeating: 0, count: arraySize)
let inputSize = MemoryLayout<UInt8>.size * input.count
let ret = IOConnectCallStructMethod(connection, Selector.mySelector.rawValue, &input, inputSize, &output, &outputSize)
This is the dispatch in the external method:
[ExternalMethodType_MyMethodRequest] =
{
.function = (IOUserClientMethodFunction) &Client::StaticHandleRequest,
.checkCompletionExists = false,
.checkScalarInputCount = 0,
.checkStructureInputSize = 200,
.checkScalarOutputCount = 0,
.checkStructureOutputSize = 200,
},
The ExternalMethod gets called and when I try to access to the input data with this:
char* input = nullptr;
size_t length = 0;
if (arguments->structureInput != nullptr)
{
input = (char*)arguments->structureInput->getBytesNoCopy();
length = arguments->structureInput->getLength();
Log("Input: %s", input);
Log("length: %zu", length);
}
If I check the variable input with a breakpoint the value is always "" and the length is 200
I tried adding the input in a struct, same result.
I tried using IOConnectCallMethod, same result.
The only alternative I can do it's making the input data extra big to force the system to use the descriptor instead of the OSData, but the input in this case would be always much smaller, so not sure if the best way to go.
Interestingly if I print the output of input with:
#define Log(fmt, ...) os_log(OS_LOG_DEFAULT, "NullDriver - " fmt "\n", ##__VA_ARGS__)
It will give me private:
NullDriver - Input: <private>
Maybe the data is actually there but I can't see it?
Further to discussion in comments:
There is no issue here with the way the data is being sent from app to dext, but rather with the way it is being logged/printed: a format string of %s is not a suitable way of printing the contents of a byte array. That treats it as a nul-terminated string (UTF-8, usually). It looks like you're sending arbitrary bytes, not a human readable string. In particular, your first byte is 0, which is how an empty C string is represented, and hence your empty output.
A format string such as "%02x %02x %02x %02x" with arguments input[0], input[1], input[2], input[3] would be more appropriate for printing the first 4 bytes; you'll have to do this in a loop, possibly writing to a buffer using snprintf before sending it to the system log, to print the entire array.
Separately: to fix the <private> issue when using %s, use %{public}s. (but read the os_log documentation on the privacy ramifications of this before you ship it)
I think the data is there but I can't see it.
If I do:
char realInput[200];
memcpy(realInput, input, 200);
When I loop printing in the debugger: realInput[i] I get my precious data

sscanf_s access violation when seperate string and integer

char a[200] = { 0 };
char tst[20] = "aaaa 123\n";
int i;
sscanf_s(tst, "%s %d",a, &i);
printf("reasult:%s %d", a,i);
No matter I use char tst[20] = "aaaa 123\n"; or char* tst = "aaaa 123\n";,
it always shows access violation.
I need to seperate a string an integer from a string. But why this happens ?
sscanf_s expects two arguments for %c, %s and %[, the second being the size of the buffer passed. The following should work:
sscanf_s(tst, "%s %d", a, sizeof(a), &i);

Storing of string literals in consecutive memory locations

#include <stdio.h>
#include <string.h>
int main() {
char *s[] = {"cricket","tennis","football"};
printf(" String are: \n\n");
printf(" %s \n", *(s));
printf(" %s \n", *(s+1));
printf(" %s \n", *(s+2));
printf(" \n\n");
printf(" Starting locations of the string are: \n\n");
printf(" %d\n",*(s));
printf(" %d\n",*(s+1));
printf(" %d\n",*(s+2));
printf(" \n\n");
return 0;
}
OUTPUT:
String are:
cricket
tennis
football
Starting locations of the string are:
134514112
134514120
134514127
s is a array of character pointers. s has three elements and each of them are storing the starting address of the string literals.i.e. s[0] is a pointer pointing to the starting address of "cricket". etc..
My question is :
By observing these addresses we can see that second string is stored just after the null character of the first string. All three strings are stored in sequential form. Is this always true ?
This is a linker decision - to store string literals tightly or not. There is no guaranties. Or even this may be done by compiler - it may create continuous data section that holds all involved literals. But nevertheless actual layout of that section is still implementation-specific and you shouldn't assume anything about it.
I have an example for you:
#include <stdio.h>
#include <inttypes.h>
char *s[] = { "ball", "football" };
int main( void )
{
int i;
for( i=0; i<2; i++ ) {
printf( "%" PRIuPTR "\n", (uintptr_t)s[i] );
// or printf( "%p\n", s[i] ); forr hex output
}
}
If I compile and run that program with gcc -O3 I get:
4195869
4195865
What happens here is that the optimizer merges both string literal to a single "football" so that s[0] becomes s[1] + 4.
That's only one example of what compiler / linker might decide on how to store string literals ...
It will be totally compiler dependent. Compiler can take any address at the time execution started
Only static arrays are contiguous in memory. ex: char s[1024].

Saving Char from lex to array of Char in C

I'm saving characters from a c file in this array
char *idTable[100];
Inside a while loop,
if(ntoken == 1){
idTable[numId] = yytext;
printf(" \nVariable %s", idTable[numId]);
printf(" Found\n");
numId++;
}
and then iterate through the array. The variable yytext is supposed to have only identifiers and variables like int i, int j, int cont
When I print those character inside the loop, it shows me the variables that I want to save. But when I iterate the array it takes all the text from the variable to the bottom:
while(i<numId){
printf("%d", i );
printf("%s", idTable[i]);
i++;
}
So,
printf(" \nVariable %s", idTable[numId]);
printf(" Found\n");
Will print characters like Variable i Found But printf("%s", idTable[i]); Will always print text inside from the file I want to see. Something like this:
i;
int j;
char c;
char cadena;
float z;
int 89aa12;
z=14.9e-8;
z= 3454y45hrthtrh;
z== 3454y45hrthtrh;
z= 3454y45hrthtrh;
z=12.9;
cadena="Hola";
scanf ("%d",i);
i=i*2;
printf ("El doble es %d",i);
Y="Cualquier Cosa 1";
u=z+y
You're saving a pointer to the same memory in each element of idTable, so whatever that memory is set to last is what each one will be pointing to.
You need to allocate additional memory for each string you want to save (or use a std::string).
strdup may do what you want.
idTable[numId] = strdup(yytext);
but don't forget to free that memory when you're done with it.

Arduino Integer error

We are trying to initialize a character array but it we get an error saying that we can not as we can not mix integers and chars, but we dont have have integers initialized.
thanks in advance
void setup()
{
Serial.begin(9600); //Set the serial monitor.
lcd.begin(16, 2); //Set the LCD
}
char line1 [5] = {0};
char line2 [] = {0};
void loop()
{
if (Serial.available() > 0) { //If the serial monitor is open it will read a value.
line1 = Serial.read();
delay(10);
Serial.print(line1);
lcd.print(line1);
}
}
I am not an arduino guy, but I did stay at a Holiday Inn last night with access to Google :)
http://arduino.cc/en/Serial/Read
Serial.read() returns a single byte (as an int). You're trying to assign that to a char array.
You can't do that. You can assign something to a specific element in an array:
line1[0] = 'c';
for example, but you can't assign to an array itself.
It seems like you're looking for Serial.readBytes()
http://arduino.cc/en/Serial/ReadBytes
Which would look like:
Serial.readBytes(line1, 5);
in your case where 5 is the length of your buffer (array). This would read (at most) 5 bytes into your line1 buffer.
Edit to add: That being said, it appears arduino's "C-Like" language is very much like C in that it expects "Strings" (char arrays) to be null terminated when passing them to Serial.print(). The advice above doesn't do that and in fact would cause problems.
What you would need to do is read up to one byte less than the length of your array, and then null terminate the "string" using the number of bytes actually read which is what bytesRead() returns to you (arrays are zero indexed):
int numBytesRead = 0;
...
numBytesRead = Serial.readBytes(line1, 4);
line1[numBytesRead] = '\0';
Serial.print(line1);
Option B is to do as I originally mentioned, but loop and print one byte at a time from your line1 array using the index:
int numBytesRead = 0;
numBytesRead = Serial.readBytes(line1, 5);
int i;
for (i = 0; i < numBytesRead; i++) {
Serial.print(line1[i]);
}
According to the docs Serial.print() automagically knows to send a single byte/char when that's all that's passed to it.