Unexpected behavior when printing out char array - c

i'm currently trying to debug my program over UART by printing the values of some variables at specific points. My issue is with printing two char arrays. The order in which i print them seems to have an effect on if it prints. The declarations of the arrays are in a struct in a header file as follows-
//header file
typedef struct
{
char latitude[10];
char longitude[11];
}NMEA_RMC_t;
NMEA_RMC_t rmc;
The char arrays are manipulated in another function after parsing data from an input. They are not updated with an interrupt, although there are interrupts elsewhere in the program. In the main code if i print them as follows-
//main program loop
printf("lat: %s \t long: %s \n", rmc.latitude, rmc.longitude);
the output to the terminal is this-
lat: +50.71735 long:
whereas if i print them in a different order like this-
printf("long: %s \t lat: %s \n", rmc.longitude, rmc.latitude);
i get this output.
long: -001.39118 lat:
also if i split the printing up into two separate printf statements, only the first print statement correctly prints the char array. I haven't had to ask for help on here before but this has had me stuck for a good week now. Any help would be massively appreciated! cheers.
edit
The part of the program that writes into the array is this. its essentially the same for the latitude and longitude array.
/* now we are in first char of latitude */
/* copy latitude chars */
strlcpy ((char*)lat, (const char*)ptr_to_comma, 10 );/*copies most size-1, null terminated*/ //changed 11 to 10
/* default latitude presentation is ddmm.mmmmm
we need to change it to dd.mmmmmmm
*/
unsigned char ind;
for (ind=0; ind<9; ind++)
{
if (*ptr_to_comma == '.')
{
ptr_to_comma++;//step over '.'
}
if ( ind==2 )
{
lat[ind++]='.';
}
lat[ind] = *ptr_to_comma;
ptr_to_comma++;
}
lat[10] = '\0'; //terminate
/* now lat == dd.mmmmmmm */
ptr_to_comma++; /*step over comma to the NS-indicator*/
/*catch NorthSouth-indicator and step*/
if ( *ptr_to_comma == 'N'){ /*if we are in the North*/
sign = '+';
rmc.ns_indicator = 'N';
} else if ( *ptr_to_comma == 'S'){ /*else we are in the South*/
sign = '-';
rmc.ns_indicator = 'S';
}
ptr_to_comma++;//step over NS-indicator
ptr_to_comma++;//step over comma to the longitude field
/* dd.mmmmmmm to dd.ddddddd */
_convert_minutes( (unsigned char*) lat+3 );
/* copy latitude with sign to the rmc-struct */
rmc.latitude[0] = sign;
strcpy ( (char*)rmc.latitude+1, (const char*)lat);
rmc.latitude[10]='\0';
essentially it is parsing the information from a stream of data coming in.

For %s to work correctly, the char array must have a NUL-terminator \0 which signifies the end of the string.
If you don't leave room for that, the behaviour of your program is undefined.
You need to initialise the arrays yourself - don't rely on the compiler to do it.
Get your debugger out and check the memory associated with rmc at the point of the printf.

Your code for converting the strings and putting them in the struct is inadvertently placing a '\0' character at the beginning of rmc.longitude. The code then goes on the fill the rest of the array with the correct value, but the printf() function sees rmc.longitude as a zero-length string and ignores what follows.
It is an an off-by-one error. rmc.latitude[10]='\0'; places a 0 in the 11th position of the rmc.latitude array, but this array was declared to only have 10 positions. What is actually happening instead is rmc.longitude[0] is getting the '\0' character, as it is adjacent in memory.

Related

Pointers and char arrays from strings

Hi I have been reading for hours and still can't grasp the conversions between
{
char i ="adf";
char foo[];
char bar[256];
}
and adding * and & makes it more confusing
I have some code that is working.
int TX_SEND(char send[])
{
unsigned char *p_tx_buffer;
p_tx_buffer = &send[0];
strcat(send, "\r");
// Write to the port
int n = write(fd,&send[0],3);
if (n < 0) {
perror("Write failed - ");
return -1;
}
return(0);
}
code is working but I need help with 2 parts.
I want to be able to run this function like kind of like printf IE TX_SEND("AT+CGMSD=STUFF"); but I am stuck
but before hand I do this alot.
char txsend[] = "at";
TX_SEND(txsend);
Also inside my TX_WRITE() I am using write(fd,&send[0],3), but it is hardcoded to send 3 bytes from send[]. I want this to be dynamic so I can just send strings at any length (realistically they will be less than 300 ASCII chars always). I tried to do something with a pointer in there but gave up (*p_tx_buffer was my beginning attempt).
i think you want
int TX_SEND(char *send)
{
int n = write(fd,send,strlen(send));
if (n < 0) {
perror("Write failed - ");
return -1;
}
return(0);
}
you cannot tack on \n to send with strcat. I would add it in the calling function, or declare an intermediate buffer and sprintf to it
like this
int TX_SEND(char *send)
{
char buff[50]; // i dont know a good max size
snprintf(buff, sizeof(buff), "%s\n", send);
int n = write(fd,buff,strlen(buff));
if (n < 0) {
perror("Write failed - ");
return -1;
}
return(0);
}
I'm not going to go through your code line-by-line, but I urge you to focus on these facts:
chars are chars and strings are strings, and never the twain shall meet. (They're totally different.)
'x' is a character constant.
"x" is a string constant.
A string is an array of characters (terminated by '\0').
When you mention an array (including a string) in a context where you need its value, what you get is a pointer to the array's first element.
When you put a & in front of something, what you get is a pointer to that something.
When you put a * in front of a pointer, what you get is the thing that the pointer points to.
Putting this together, we could write
char str[] = "xyz";
char *p = str; /* per rule 5, this is fine, and p gets a pointer to str's first element */
char c = *p; /* per rule 7, c gets the first character of str, which is 'x' */
printf("%c\n", c);
If you're just starting with C, you may not have come across rule 5 yet. It will probably surprise you at first. Learn it well, though: you'll never understand arrays and pointers in C without it.

Array point 0 doesn't reset content

I've made use of an array, and want to delete the content by placing null in array[0] but it doesn't work. Example... If I type Jesper, then the serial.print(nameBuffer[1]) returns e.
A temporary solution I use is a for-loop to place null in all it's spaces.
char name1[9] = "Jesper";
char nameBuffer[9];
void setup()
{
Serial.begin(9600);
}
void loop()
{
int i = 0;
nameBuffer[0] = 0;
Serial.print(nameBuffer[1]);
Serial.println(" All reset\n");
while(Serial.available() == 0)
{
// wait for data to be send
}
while(Serial.available() > 0)
{
int inByte = Serial.read();
delay(50);
nameBuffer[i] = char(inByte);
i++;
Serial.print("Recieved bytes: ");
Serial.println(inByte,DEC);
}
Serial.print("Searching for: ");
Serial.println(nameBuffer);
}
nameBuffer is an array of 9 char elements. Each of those elements has a value of type char.
Setting a char object to 0 doesn't remove it from the array (0 or '\0', the null character, is as valid a char value as any other), nor does it affect the elements that follow it.
Now if you're treating the contents of nameBuffer as a string (defined by the C standard as "a contiguous sequence of characters terminated by and including the first null
character"), then storing '\0' in nameBuffer[0] will cause it to contain an empty string. It has a length of 0, but there are still 9 char values stored in the array. So this:
printf("%s", nameBuffer);
won't print anything, but namebuffer[1] is still a valid char object holding whatever value was last stored in it.
Don't assume that printing a null character, or sending it over a serial port, will do nothing. If you don't want to print each character in your array, you'll need some logic to avoid printing the characters you don't want.
Incidentally, your code appears to be C++, not C. You have overloaded versions of Serial.print, one taking a char argument and one taking a char*; C doesn't support overloading. And char(inByte) is C++; it's a syntax error in C. (BTW, a cast isn't necessary there; the value will be converted implicitly.)

sscanf function changes the content of another string

I am having problems reading strings with sscanf. I have dumbed down the code to focus on the problem. Below is a function in the whole code that is supposed to open a file and read something. But sscanf is acting strangely. For instance I declare a string called atm with the content 'ATOM'. Before the sscanf it prints this string as ATOM while after it is null. What could be the problem? I assume it must be an allocation problem but I could not find it. I tried some suggestions on other topics like replacing %s with other things but it did not help.
void Get (struct protein p, int mode, int type)
{
FILE *fd; //input file
char name[100]="1CMA"; //array for input file name
char string[600]; //the array where each line of the data file is stored when reading
char atm[100]="ATOM";
char begin[4];
int index1 =0;
fd = fopen(name, "r"); // open the input file
if(fd==NULL) {
printf("Error: can't open file.\n");
return 1;
}
if( type==0 ) { //pdb file type
if( mode==0 ) {
while( fgets(string, 600, fd)!=NULL ) {
printf("1 %s\n",atm);
sscanf (string, "%4s", begin );
printf("2 %s \n",atm);
}
}
}
fclose(fd);
free(fd);
free(name);
}
The string begin isn't big enough to hold the four characters that sscanf will read and its \0 terminator. If the \0 is written into atm (depending on where the strings are in memory), atm would be modified. From the sscanf manpage, about the s directive:
s    Matches a sequence of non-white-space characters; the next pointer must be a pointer to character array that is long enough to hold the input sequence and the terminating null byte ('\0'), which is added automatically. The input string stops at white space or at the maximum field width, whichever occurs first.
I was able to reproduce this behavior on my machine, though the exact positioning of the strings in memory was a bit different. By printing the addresses of the strings, though, it is easy to figure exactly what's happening. Here's a minimal example:
#include<stdio.h>
int main() {
char begin[2];
char atm[100]="ATOM";
printf("begin: %p\n", begin);
printf("begin+16: %p\n", begin+16);
printf("atom: %p\n", atm);
printf("1 %s\n",atm);
sscanf("AAAABBBBCCCCDDDD", "%16s", begin);
printf("2 %s \n",atm);
return 0;
}
This produces the output:
$ ./a.out
begin: 0x7fffffffe120
begin+16: 0x7fffffffe130
atom: 0x7fffffffe130
1 ATOM
2
I printed the values of the pointers to figure out how big a string it would take to overflow into atm. Since (on my machine) atom begins at begin+16, reading sixteen characters into begin puts a null terminator at begin+16, which is the first character of atm, so now atm has length 0.

character array is not getting printed using %s

1.While I am trying to display conv it is not showing anything, but when i print one one element using subscript i am able to see the contents.
2. Program to convert decimal to binary, octal, hexadecimal
#include<stdio.h>
int main()
{
convbase(23,2);
return 0;
}
int convbase(int num, int base)
{
char conv[33] = {' '};
char *ptr = &conv[32];
conv[32] = '\0';
do
{
*--ptr = "0123456789ABCDEF"[num % base];
num = num/base;
}while(num);
if(base == 16)
{
*--ptr = 'x';
*--ptr = '0';
}
if(base == 8)
{
*--ptr = '0';
}
printf("Decimal to base %d is :\t%s\n",base,conv);
return 0;
}
change
printf("Decimal to base %d is :\t%s\n",base,conv);
to
printf("Decimal to base %d is :\t%s\n",base,ptr);
or
move the contents (ptr - to end of string) to start of conv array
another alternative is to instead of writing from end of conv to write from start and then when you are done call strrev() to reverse it.
printf("Decimal to base %d is :\t%s\n",base,strrev(conv));
You are filling your array from the end towards the front. In your example, the bit string is in the array elements 27...31. Thus, the 1st element contains \0, and the char array will be considered as an empty string, and nothing is printed.
You can check this easily by setting a breakpoint at the print statement.
You most propably assume that the following line initialises conv to all blanks:
char conv[33] = {' '};
This is not the case. With the above code conv has its first byte set to blank and all other bytes set to 0. So the result would only be printed if it had at least 31 digits.
You might consider using the follwong code to intialise conv:
char conv[33] = {0}; /* default init: set conv to all zeros */
memset(conv, ' ', sizeof(conv) - 1); /* re-set all but the last to blank */
This line:
conv[32] = '\0';
is not needed anymore than.
I do agree with Reinhard Männer that using a debugger would have helped you a lot to finding this out by yourself.
I think you're doing one -- too much.
While building the string, ptr always points to where you're going to write the next character (if there is a next character). This place is always initialized with null bytes (except for conv[0], which is a space.
So when calling printf, ptr points to null bytes, which is an empty string.
ptr++ before printf should solve it.
I do agree with #alk.
You were initializing only the first element of the array with blank and other elements were initialized to 0 because of which you were getting blank line.
Actually line is not blank, printf prints only first character which is blank ' ' and when it encounter 0 it stops.
You can verify it by replacing ' ' with any other character. ofcourse except '\0'

Passing Variables through functions C

Hello im just beginning to learn C and i want to know why im getting a problem here..
i wish to pass a char pointer
char *temp;
into a function ie call to function
checkIfUniqueCourseNo(temp,k);
with a prototype
int checkIfUniqueCourseNo(char checkchar[4],int);
and a function header
int checkIfUniqueCourseNo(char checkchar[4], int k)
Im sure im doing something really stupid here but im not sure how to fix it :(
thanks in advance. ps my error is that checkchar[4] outputs a P...
Example---
temp = "123A"
checkIfUniqueCourseNo(temp,k);
int checkIfUniqueCourseNo(char checkchar[4], int k){
printf("CheckifUniqueCourse\n");
printf("Check Value = %c \n", checkchar);
return 0;
}
Output = Check Value = P
temp = "123A"
checkIfUniqueCourseNo(temp,k);
int checkIfUniqueCourseNo(char checkchar[4], int k){
printf("CheckifUniqueCourse\n");
printf("Check Value = %c \n", checkchar);
^^^^^^^^^
return 0;
}
If you're trying to print out the first character of checkchar, then you need to change this line to either
printf("Check Value = %c\n", *checkchar);
or
printf("Check Value = %c\n", checkchar[0]);
In the context of a function parameter declaration, T a[N] and T a[] are equivalent to T *a; a is declared as a pointer to T, not an array of T.
When you wrote
printf("Check Value = %c\n", checkchar);
you lied to printf; you said the argument is supposed to be of type char, but you passed a char *. Hence the bogus output.
If you want to print out the entire string "1234", then you need to change that line to
printf("Check value = %s\n", checkchar);
This time we use the %s conversion specifier to tell printf that checkchar points to a 0-terminated array of char (a.k.a. a string).
This is not at all clear. Are you assigning any value to temp? If so, what?
It would make more sense to have your prototype as:
int checkIfUniqueCourseNo(char* checkchar, int);
Since it's not at all clear where you got the 4 from.
It's been a while since I've done C, but I can see a few problems here, temp = "123A" actually requires an array for 5 characters (one of which is to include the '\0' string terminating character).
Secondly, the line printf("Check Value = %c \n", checkchar); seems to be trying to print a memory pointer as a character, change it to the following: printf("Check Value = %s \n", checkchar); and it will output each character in the array until it hits the terminating character.
There are a couple of things to look at here, you need to take a good look at the data you have, how it is represented and what you want to do with it.
Your course code appears to be a four character string, you should know that traditionally, strings in C also include an extra byte at the end with the value of zero (NUL) so that the many string functions that exist know that they have reached the end of the string.
In your case, your four digit code takes up five bytes of memory. So wont fit well passing it into your function.
If I were you, I would pass in a pointer like so:-
int checkIfUniqueCourseNo(char* coursecode, int k ) {
int rv = -1;
if ( coursecode == NULL ) return rv;
//...
I have no idea what K is for, do you?
Once you have your sequence of bytes inside your function you can save yourself alot of hastle later by doing some simple bounds checking on the data like so:
//...
if ( strlen(coursecode) > 4 ){
fprintf(stderr,"course code too long\n");
return rv;
}
if ( strlen(coursecode) < 4 ){
fprintf(stderr,"course code too short\n");
return rv;
}
//...
You can be sure you have a 4 character string now..

Resources