strstr() function returns the address 0x0000 - c

I'm trying to check whether (and where) a substring ("DATA") is located in a big string (located in a buffer - linearBuffer) by strstr() function, but it doesn't seem to work and I don't know why eventhough my source string (located in the linearBuffer) in null terminated.
What really happended is that a ringbuffer (buf) fills with characters for every USART interrupt. Then, in some point of the code its content copied into a linear buffer (through ringBuff_to_linearBuff()) and I apply the strstr() function on it in order to find a wanted substring. The value that I get when the function strstr() returns is the value 244 and not the location of the substring eventhough I know its there from setting a breakpoint
** Note that my code is spread on many files so I tried to gather all question related code together.
#include <string.h>
#define BUFFER_SIZE 400
#define LINEAR_BUFFER_SIZE (BUFFER_SIZE+1)
#define WIFI_CMD_DATA "DATA"
typedef RingBuff_Data_t uint8_t;
typedef struct
{
RingBuff_Data_t Buffer[BUFFER_SIZE]; /**< Internal ring buffer data, referenced by the buffer pointers. */
RingBuff_Data_t* In; /**< Current storage location in the circular buffer */
RingBuff_Data_t* Out; /**< Current retrieval location in the circular buffer */
} RingBuff_t;
volatile RingBuff_t buf;
uint8_t linearBuffer[LINEAR_BUFFER_SIZE]="";
static inline void RingBuffer_Insert(RingBuff_t* const Buffer, const RingBuff_Data_t Data)
{
*Buffer->In = Data;
if (++Buffer->In == &Buffer->Buffer[BUFFER_SIZE])
Buffer->In = Buffer->Buffer;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
Buffer->Count++;
}
}
ISR(USART1_RX_vect)
{
//code to be executed when the rx pin of the USART receives a char
uint8_t c = UDR_N;
if (c != '\n')
RingBuffer_Insert(&buf,c);
else
RingBuffer_Insert(&buf,'\0');
}
void ringBuff_to_linearBuff(uint8_t linearBuffer[])
{
memset(linearBuffer,0,LINEAR_BUFFER_SIZE);
RingBuff_Data_t* tempIn = buf.In;
if (buf.Out < tempIn){
memcpy(linearBuffer, buf.Out, tempIn - buf.Out);
}
else if (buf.Out > tempIn){
size_t s1 = buf.Buffer + BUFFER_SIZE - buf.Out;
size_t s2 = buf.In - buf.Buffer;
memcpy(linearBuffer, buf.Out, s1);
memcpy(linearBuffer + s1, buf.Buffer, s2);
}
}
void main ()
{
uint8_t* linearBufferp;
while (1)
{
if (buf.Out != buf.In)
{
ringBuff_to_linearBuff(linearBuffer);
linearBufferp = strstr(linearBuffer, WIFI_CMD_DATA); // Checking if a new DATA msg from a client had arrived
if (linearBufferp != NULL)
{
//do something
}
}
}
}
debugging

When strstr returns NULL it means that it didn't find the substring (and when that happens, the value it points to have no meaning at all, so forget about the 224).
So your question should be:
Why doesn't strstr find my substring?
When looking at the debug picture you posted, your linearBuffercontains:
13
0
13
0
43
....
....
68 <---- This is what you want to find
65
....
However, there are multiple strings in your buffer:
13 <----- Start of first string
0 <----- End of first string
13 <----- Start of second string
0 <----- End of second string
43 <----- Start of thrid string
....
....
68 <---- This is what you want to find
65
....
strstr will only search the first string. When strstr sees the first 0 (index [1]), it returns NULL because it didn't find what it was looking for.
In other words - strstr never looks at the part of the buffer where the match is. It returns long before that.
So what's wrong with your code?
It is hard to say since you haven't posted a complete code base. So this is a guess. I think you receive a number of "newlines" in the form:
13 10 13 10
before the message. So you receive:
13 10 13 10 43 ...... 68 65 .....
Your ISR turns the 10 into 0 so the buffer becomes
13 0 13 0 43 ...... 68 65 .....
which is 3 strings instead of 1 string.
What to do?
Well, there could be several different solutions. The correct depends on your system requirements. A simple solution would be to skip the extra 13 0 before calling strstr. Something like:
ringBuff_to_linearBuff(linearBuffer);
// Skip "13 0"
while (*linearBuffer == 13 && *(linearBuffer+1) == 0)
{
linearBuffer += 2;
}
linearBufferp = strstr(linearBuffer, WIFI_CMD_DATA);
Note: You should add some range check also so that linearBuffer isn't incremented so much that you read out of bounds

Related

Reading bytes from progmem

I'm trying to write a simple program (as a pre-cursor to a more complicated one) that stores an array of bytes to progmem, and then reads and prints the array. I've looked through a million blog/forums posts online and think I'm doing everything fine, but I'm still getting utter gibberish as output.
Here is my code, any help would be much appreciated!
void setup() {
byte hello[10] PROGMEM = {1,2,3,4,5,6,7,8,9,10};
byte buffer[10];
Serial.begin(9600);
memcpy_P(buffer, (char*)pgm_read_byte(&hello), 10);
for(int i=0;i<10;i++){
//buffer[i] = pgm_read_byte(&(hello[i])); //output is wrong even if i use this
Serial.println(buffer[i]);
}
}
void loop() {
}
If I use memcpy, I get the output:
148
93
0
12
148
93
0
12
148
93
And if I use the buffer = .... statement in the for loop (instead of memcpy):
49
5
9
240
108
192
138
173
155
173
You're thinking about two magnitudes too complicated.
memcpy_P wants a source pointer, a destination pointer and a byte count. And the PROGMEM pointer is simply the array. So, your memcpy_P line should like like
memcpy_P (buffer, hello, 10);
that's it.
memcpy (without the "P") will not be able to reach program memory and copy stuff from data RAM instead. That is not what you want.

Is there a way to easily check if a string is filled with either spaces / tabs / EOL and nothing else? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I am creating a program where I read lines 1 by 1 from a file. I wanted to implement a check where after the line is read and stored in a string it is checked to see if any one of its characters are not a space/tab/EOL. So essentially what I am trying to do is skip over the line and not store it if the entire line doesn't have any content other then spaces/tabs/EOL's.
Use strpbrk to search characters in a string. Returns a pointer to the position of the first occurrence or NULL if none found.
http://www.tutorialspoint.com/c_standard_library/c_function_strpbrk.htm
Let's call your string buffer and let's go through it one character at a time.
char *tmp = buffer; // give tmp the address of the buffer's first character.
// Assuming you have bool defined.
// If you don't, just switch this with whatever you prefer to use for bools.
bool bHasValidChar = false;
while(*tmp){
if(*tmp != ' ' && *tmp != '\t' && *tmp != '\n'){
// Cool, this character is not whitespace
bHasValidChar = true;
break;
}else{
// The character is whitespace
// Move on and test the next character
tmp++;
}
}
if(bHasValidChar){
// Contains non-whitespace. Do something.
}else{
// Str is only whitespace. Do something.
}
If you don't have bool (you may not have it if you're using an old version of C), then use an int instead of bool (with 1 & 0 in place of true and false), or whatever you prefer.
Hope this helps.
Note: This was typed off of my phone, so it has not been tested. I apologize for any errors in my post & code, but hopefully this will get you started down the right direction.
3 ways: see if any non-white-space exist
char nws[2];
if (sscanf(buf, "%1s", nws) == 1) foo(buf);
else skip(); // all white-space
// or if code wants to use specific ws characters
if (buf[strspn(buf, " \t\r\n")] != '\0') skip();
int Interesting(const char *s) {
// Take advantage that the null character is not a white-space
while (isspace((unsigned char) *s)) {
s++;
}
return *s;
}
Basically, you need to loop over the string until the end or until you find a character that is not one of the "allowed characters":
char only_whitespace(char const * str /* NULL terminated */) {
for (; *str; ++str) {
switch (*str) {
case 32: /* space */
case 9: /* TAB */
case 10: /* line feed */
case 13: /* carriage return, windows... */
break;
default: return 0;
}
}
return 1;
}
If you want to be the cause of some WTFs in the future (by the one maintaining your code, this could also be your future self), add this for extra speed:
char only_whitespace(char const * str /* NULL terminated */) {
for (; *str; ++str) {
if ((*str >> 6) || (*str & 16)) {
return 0;
}
switch (*str) {
case 32: /* space */
case 9: /* TAB */
case 10: /* line feed */
case 13: /* carriage return, windows... */
break;
default: return 0;
}
}
return 1;
}
Reason:
0b00100000 = 32
0b00001001 = 9
0b00001010 = 10
0b00001101 = 13
0b00010000 = 16
Wait a second...
I am creating a program where I read lines 1 by 1 from a file. [..]
If you're reading line by line, then there won't be any "end of line" character(s) in your line. That's the point of reading line by line. So you only need to check for space or tab characters.
With this, we can also go crazy:
0b00100000 = 32 (space)
0b00001001 = 9 (tab)
---------- bitwise or
0b00101001
---------- bitwise not
0b11010110 = 0xD6 (mask of bits that must not be set)
Now, assuming a 64-bit architecture, we can replicate that bit mask 8 times and use it to do a quick "pre scan" of the string, speeding up the check if we expect a high rate of strings that do not only consist of whitespace characters. Though we should know the length before, otherwise obtaining the length will probably ruin any performance gains:
char only_whitespace_with_prescan64(char const * const str /* one line */, size_t length) {
uint64_t const * cursor = (uint64_t const *) str;
uint32_t mask32 = 0xD6 | (0xD6 << 8) | (0xD6 << 16) | (0xD6 << 24);
uint64_t mask64 = ((uint64_t) mask32) << 32 | mask32;
for (; length != 0; --length, ++cursor) {
if (*cursor & mask64) {
return 0;
}
}
return only_whitespace(str);
}
Though whether this really brings any (noticeable) performance gain depends both on the frequency of its use and of course on the type of data you expect. Using stuff like that should only be done when you noticed while profiling your program that the function is actually a performance bottleneck.
NOTE: All of the above code is entirely untested.

C reading file using ./a.out<filename and how to stop reading

In my class today we were assigned a project that involves reading in a file using the ./a.out"<"filename command. The contents of the file look like this
16915 46.25 32 32
10492 34.05 56 52
10027 98.53 94 44
13926 32.94 19 65
15736 87.67 5 1
16429 31.00 58 25
15123 49.93 65 38
19802 37.89 10 20
-1
but larger
My issue is that any scanf used afterwards is completely ignored and just scans in what looks like garbage when printed out, rather than taking in user input. In my actual program this is causing an issue with a menu that requires input.
How do I get the program to stop reading the file provided by the ./a.out"<"filename command?
also I stop searching at -1 rather than EOF for the sake of not having an extra set of array data starting with -1
ex
-1 0 0 0
in my real program the class size is a constant that is adjustable and is used to calculate class averages, I'd rather not have a set of 0's skewing that data.
#include <stdio.h>
int main(void)
{
int i = 0,j = 1,d,euid[200],num;
int tester = 0;
float hw[200],ex1[200],ex2[200];
while(j)
{
scanf("%d",&tester);
if( tester == -1)
{
j = 0;
}
else
{
euid[i] = tester;
}
scanf("%f",hw+i);
scanf("%f",ex1+i);
scanf("%f",ex2+i);
i++;
}
for(d = 0;d < 50;d++) /*50 because the actual file size contains much more than example*/
{
printf("euid = %d\n",euid[d]);
printf("hw = %f\n",hw[d]);
printf("ex1 = %f\n",ex1[d]);
printf("ex2 = %f\n",ex2[d]);
}
printf("input something user\n");
scanf("%d",&num);
printf("This is what is being printed out -> %d\n",num);
return 0;
}
I'm having the exact same problem. Tried every method I could find to eat the remaining input in the buffer, but it never ends.
Got it to work using fopen and fscanf, but the prof. said he prefers the code using a.out < filename
Turns out this is in fact not possible.

Getting stange error with strings

I'm writing a program in C for my beaglebone black to manipulate the gpio pins. This is a very crude program but its just a "beta" if you will. Just to get it up and running. My problem is that I have two character arrays. One holding a command to be passed to the system() function and another holding the path of the file that I am going to be editing, it goes to the fopen function. These character arrays are manipulated to change two numbers depending on what is passed to them from the calling function. For some reason the filename character array is being concatenated with the command. I'm skimming through the program but i don't see any obvious errors.
Here is my code
/*
* gpio.c
*
* Created on: Aug 26, 2014
* Author: Christian Macias
*
* Description: This will control your GPIO (General Purpose IO) pins on the beagle bone. Please
* ensure you are on a kernel that supports device trees.
*
* Usage: gpio(PIN, Value "1" or "0", Inverted? "0" false or "1" for true)
*
* The return value is 0 for success and -1 for failure
*
* GO UTEP!!
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int gpio(int pin, int value, int inv)
{
int sucfail=0;
int pinInt1, pinInt2=-1;
int counterOne=NULL;
char filename[28]= "/sys/class/gpio/gpio00/value";//27 characters
/*
* Checks if file is within the gpio pin range.
*/
if(pin<0 || pin>=99)
{
fprintf(stderr, "\n%s\n\t%s\n\t%s\n", "Error in gpio.c(GPIO): ", "The gpio pin selected is not "
"within the availabilty of the app", "Please select a pin from 0-99");
return -1;
}
/*
* checks to see if value is boolean aka 1 or 0
*/
if(value<0 || value>1)
{
fprintf(stderr, "\n%s\n\t%s\n\t%s", "Error in gpio.c(GPIO): ", "The Selected value is invalid", "Please"
" select a 1 or a 0");
return -1;
}
/*
* Writes the pin to a file so that it can used later
*/
FILE *PINWRITE;
PINWRITE=fopen("pinWRITE", "w+");
fprintf(PINWRITE,"%i", pin);
fclose(PINWRITE);
/*
* This section will check for pre-existence of the the PIN file to prevent errors. or
* opens it if it doesnt exist.
* First it will set up the filenames
*/
PINWRITE=fopen("pinWRITE","r");
fscanf(PINWRITE, "%1i%1i", &pinInt1, &pinInt2);//Checks the pin and sets each digit to its according variable
fclose(PINWRITE);
filename[20]='0'+pinInt1;
if(pinInt2==-1)//If it is a one digit pin, it will move the letters to fit the file name correctly and remove one of the digits
{
for(counterOne=21;counterOne<28;counterOne++)
{
filename[counterOne]=filename[counterOne+1];
}
filename[27]='\0';
}
else//If two digits it will just change the second digit
{
filename[21]='0'+pinInt2;
}
FILE *PINVALUE;//FILE pointer to the files with the value
PINVALUE=fopen(filename,"w+");
/*
* At this point the the actual checking and creation occurs
*/
char exportCommand[32]="echo 00 > /sys/class/gpio/export";//31 characters
if(PINVALUE==NULL)
{
//this runs if the file didnt exist.
exportCommand[5]='0'+pinInt1;
if(pinInt2==-1)//If it is a one digit pin, it will move the letters to fit the file name correctly and remove one of the digits
{
for(counterOne=6;counterOne<32;counterOne++)
{
exportCommand[counterOne]=exportCommand[counterOne+1];
}
exportCommand[31]='\0';
}
else//If two digits it will just change the second digit
{
exportCommand[6]='0'+pinInt2;
exportCommand[32]='\0';
}
system(exportCommand);
printf("\n%s\n", exportCommand);
printf("\n%s\n", filename);
PINVALUE=fopen(filename,"w+");
}
if(PINVALUE==NULL)
{
fprintf(stderr,"\n%s\n\t%s", "Error in gpio.c(GPIO)", "The PINVALUE (.../gpioXX/value) could not be opened");
return -1;
}
/*
* Some pins may be set up backward... on is off and off is on. To correct this we must adjust a file...
* This takes to long and i dont have the time for it so i'm doing a hot fix... sorry but its 11 and i have
* school tomorrow. The correction process it too long and i want to finish today :)
*/
if(inv==1 && value==1)
{
value=0;
}
else if(inv==1 && value==0)
{
value=1;
}
/*
* At this point the file is set up and ready to be written to.
* We will write the value now and close it.
*/
fprintf(PINVALUE, "%i", value);
fclose(PINVALUE);
return sucfail;
}
You are underestimating the length of string literals you want to copy into arrays, leaving no space for the nul terminator. For example, here
char filename[28]= "/sys/class/gpio/gpio00/value"; //27 characters
the literal actually has 28+1 characters (28 visible, plus a nul terminator).
You need to make the array of size 29. You can do this explicitly,
char filename[29] = "/sys/class/gpio/gpio00/value";
or implicitly:
char filename[] = "/sys/class/gpio/gpio00/value";
Similarly here, where you need the array to be of length 33:
char exportCommand[32]="echo 00 > /sys/class/gpio/export";
There may well be other errors. I would start by fixing those first. It will make finding the other ones easier.

Using strcat to append spaces. Compiles but overwrites string

The language I am working in is C.
I am trying to use a mix of built in c string functions in order to take a list of tokens (space separated) and "convert" it into a list of tokens that is split by quotations.
A string like
echo "Hello 1 2 3 4" test test2
gets converted to
[echo] ["Hello] [1] [2] [3] [4"] [test] [test2]
I then use my code (at bottom) to attempt to convert it into something like
[echo] [Hello 1 2 3 4] [test] [test2]
For some reason the second 'token' in the quoted statement gets overridden.
Here's a snippet of the code that runs over the token list and converts it to the new one.
88 for (int i = 0; i < counter; i++) {
89 if ( (strstr(tokenized[i],"\"") != NULL) && (inQuotes == 0)) {
90 inQuotes = 1;
91 tokenizedQuoted[quoteCounter] = tokenized[i];
92 strcat(tokenizedQuoted[quoteCounter]," ");
93 } else if ( (strstr(tokenized[i],"\"") != NULL) && (inQuotes == 1)) {
94 inQuotes = 0;
95 strcat(tokenizedQuoted[quoteCounter],tokenized[i]);
96 quoteCounter++;
97 } else {
98 if (inQuotes == 0) {
99 tokenizedQuoted[quoteCounter] = tokenized[i];
100 quoteCounter++;
101 } else if (inQuotes == 1) {
102 strcat(tokenizedQuoted[quoteCounter], tokenized[i]);
103 strcat(tokenizedQuoted[quoteCounter], " ");
104 }
105 }
106
107 }
In short, adding an space to a char * means that the memory pointed by it needs more bytes. Since you do not provide it, you are overwritting the first byte of the following "word" with \0, so the char * to it is interpreted as the empty string. Note that writting to a location that has not been reserved is an undefined behavior, so really ANYTHING could happen (from segmentation fault to "correct" results with no errors).
Use malloc to create a new buffer for the expanded result with enough bytes for it (do not forget to free the old buffers if they were malloc'd).

Resources