I have a structure like this:
typedef struct {
char gpsTime[6];
char gpsStatus[1];
char gpsLat[10];
char gpsLong[10];
char gpsSpeed[5];
char gpsDate[6];
} gpsData;
and also a string at which I would like to concatenate the elements of this structure:
#define MESSAGESIZE 100
// Final message to be sent
char message[MESSAGESIZE]="$STARTOFMSG,23,";
The problem is, when I use "strcat" function like this:
strcat(message,data.gpsTime);
I expect to have something like this:
"$STARTOFMSG,23,083559";
but the total elements of structure are concatenated, i.e.:
"$STARTOFMSG,23,,083559A4717.1143700833.91520.004091202##";
I guess this is a problem with pointers. How should I solve this?
I guess gpsTime is not properly terminated, i.e. it's not a valid C string. This will cause undefined behavior.
If you expect it to be "083559" as shown, it cannot be char gpsTime[6] since that leaves no room for the terminator. It has to be char gpsTime[7] or more. This of course goes for all of the strings; a C string with n characters has to have n + 1 chars worth of space since the final one must be \0 to terminate the string.
strcat copies the string up to the /0 termination character. Add the termination char and it should work.
083559 is already 6 character, so you need to define gpsTime as char gpsTime[7] and add the /0 termination character.
Related
Is there any C library function that copies a char array (that contains some '\0' characters) to another char array, without copying the '\0'?
For example, "he\0ll\0o" should be copied as "hello".
As long as you know how long the char array is then:
void Copy(const char *input, size_t input_length, char *output)
{
while(input_length--)
{
if(input!='\0')
*output++ = input;
input++;
}
*output = '\0'; /* optional null terminator if this is really a string */
}
void test()
{
char output[100];
char input = "He\0ll\0o";
Copy(input, sizeof(input), output);
}
No, there is no library function that does that. You have to write your own.
One question though: how do you know when to stop ignoring \0? Your string ("he\0ll\0o") has three zero bytes. How do you know to stop at the third?
'\0' in strings is a method to find the end of the string(terminating character for strings). So, all the functions designed for string operations use '\0' to detect end of string.
Now, if you want such implementation as you have asked, you need to design of your own.
Problem you will face is:
1) how will you determine which '\0' is used as a terminating character?
So for such implementation, you need to explicitly tell the count of '\0' used as terminating character or you need to set your own terminating character for strings.
2) For any other operations on your implementation, you cannot use predefined string related functions.
So, Implement your own functions to do those operations.
I am appending a string using single character, but I am not able to get it right. I am not sure where I am making mistake. Thank you for your help in advance. The original application of the method is in getting dynamic input from user.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main(){
int j;
char ipch=' ';
char intext[30]="What is the problem";
char ipstr[30]="";
printf("Input char: ");
j=0;
while(ipch!='\0'){
//ipch = getchar();
ipch = intext[j];
printf("%c", ipch);
strcat(ipstr,&ipch);
j++;
}
puts("\n");
puts(ipstr);
return;
}
Following is the output I am getting.
$ ./a.out
Input char: What is the problem
What is h e
p
oblem
change
strcat(ipstr,&ipch);
to
strncat(ipstr, &ipch, 1);
this will force appending only one byte from ipch. strcat() will continue appending some bytes, since there's no null termination character after the char you are appending. as others said, strcat might find somewhere in memory \0 and then terminate, but if not, it can result in segfault.
from manpage:
char *strncat(char *dest, const char *src, size_t n);
The strncat() function is similar to strcat(), except that
it will use at most n characters from src; and
src does not need to be null-terminated if it contains n or more characters.
strcat requires its second argument to be a pointer to a well-formed string. &ipch does not point to a well-formed string (the character sequence of one it points to lacks a terminal null character).
You could use char ipch[2]=" "; to declare ipch. In this case also use:
strcat(ipstr,ipch); to append the character to ipstr.
ipch[0] = intext[j]; to change the character to append.
What happens when you pass &ipch to strcat in your original program is that the function strcat assumes that the string continues, and reads the next bytes in memory. A segmentation fault can result, but it can also happen that strcat reads a few garbage characters and then accidentally finds a null character.
strcat() is to concatenate strings... so passing just a char pointer is not enough... you have to put that character followed by a '\0' char, and then pass the pointer of that thing. As in
/* you must have enough space in string to concatenate things */
char string[100] = "What is the problem";
char *s = "?"; /* a proper '\0' terminated string */
strcat(string, s);
printf("%s\n", string);
strcat function is used to concatenate two strings. Not a string and a character. Syntax-
char *strcat(char *dest, const char *src);
so you need to pass two strings to strcat function.
In your program
strcat(ipstr,&ipch);
it is not a valid statement. The second argument ipch is a char. you should not do that. It results in Segmentation Fault.
i ve tried almost everything but i cant solve this problem. I have a struct:
typedef struct{
char firstname[15];
char lastname[20];
char status[1];
char dateOfBirth[10];
} Rec;
and a main:
int main()
{
Rec rec;
strcpy(rec.status,"M");
strcpy(rec.dateOfBirth,"14-11-2000");
strcpy(rec.firstname,"Peter");
strcpy(rec.lastname,"Something");
printf("%s, %s, %s, %s\n", rec.status,rec.dateOfBirth,rec.firstname,rec.lastname);
return 0;
}
So this, should print -> M, 14-11-2000, Peter, Something ..but it doesnt!
It prints -> M14-11-2000, 14-11-2000, Peter, Something.
In other words the "status" member gets "corrupted".
I noticed that if i change the order of the struct's data , the output changes but there is always a data that gets corrupted.
Is there anything wrong in the way that i define my struct? Thx!
You need to make the char arrays 1 byte longer to allow for the null terminator. In particular, the status and dateOfBirth fields should be 2 and 11 bytes respectively based on how you are using them. strcpy copies the given data plus 1 null terminator byte. Without that, the strcpy ends up writing one byte past that member (which would likely be the very next member in this case since char arrays would likely end up with one byte alignment).
In C a string is a char array terminated with a 0-byte, so your char arrays need to be one byte longer.
Your char arrays status and dateOfBirth are too short; you need to account for the terminating null character.
It's because your char arrays are missing null terminators (the status buff doesn't have space for one). printf continues printing til it encounters a null terminator, it does no bounds checking.
I'm getting the following error with memcpy. It doesn't give compilation error but doesn't give the result I would imagine. I've never used memcpy before so I'm sure I'm making a simple mistake. I've looked around previous questions but couldn't find one with structures. I can use memcpy on independent variables but just not on structs.
If someone can point out my mistake it'll be great.
#include <stdio.h>
#include <string.h>
int main() {
struct st{
char c1[12];
char c2[32];
char c3[3];
char c4[7];
char c5[13];
char c6[5];
char c7[10];
};
struct st s;
char s1[] = "part number";
char s2[] = "j9uijd9d09fj";
char s3[] = "abc";
char s4[] = "seven";
char s5[] = "aaaaaaaa";
char s6[] = "ptype";
char s7[] = "user";
memcpy(s.c1,s1,sizeof(s.c1));
memcpy(s.c2,s2,sizeof(s.c2));
memcpy(s.c3,s3,sizeof(s.c3));
memcpy(s.c4,s4,sizeof(s.c4));
memcpy(s.c5,s5,sizeof(s.c5));
memcpy(s.c6,s6,sizeof(s.c6));
memcpy(s.c7,s7,sizeof(s.c7));
printf("%s\n",s.c1);
printf("%s\n",s.c2);
printf("%s\n",s.c3);
printf("%s\n",s.c4);
printf("%s\n",s.c5);
printf("%s\n",s.c6);
printf("%s\n",s.c7);
return 0;
}
OUTPUT I'm getting :
part number
j9uijd9d09fj
abcseven
seven
aaaaaaaa
ptypeuser
user
Thanks!!!
Change the size of c3 in your struct to 4 and c6 to 6 to allow for the NULL terminator.
struct st{
char c1[12];
char c2[32];
char c3[4]; /* putting 'abc' which is 4 chars */
char c4[7];
char c5[13];
char c6[6]; /* putting 'ptype' which is 6 chars */
char c7[10];
};
printf with %s prints a null-terminated string. s3 (and s6) in this case has the null-terminating character overwritten by c so printf stops printing it when it reaches the next one, which is after seven.
Your code is wrong for two things:
s.c3 is 3 characters in length, so there is no room for the extra NUL byte. That's why you get it concatenated with the next one on printing.
In some cases, you are copying more bytes than there is in the original string: memcpy(s.c2,s2,sizeof(s.c2)) is copying 32 bytes, but the original string is far shorter. That is undefined behaviour.
Probabl you want to use strcpy().
Or even strncpy, but beware! this functions does not do what most people think... Read the documentation at least twice before using it.
In the structure the member c3 is an array of three characters. You then copy four characters into it! Remember that strings have an extra character that ends the string, so the string "abc" is actually four characters: 'a', 'b', 'c' and the terminator '\0'.
The same for the c6 member of the structure.
The problem you are facing is the missing NUL-terminator of the character sequences.
A character sequence as you constructor them, is always one character longer then the amount of characters you types in. The additional character at the end is the NUL-terminator.
So the arrays you copy your thing in, need to be one character longer then the amount of characters you want to copy in. For c3 the amount of characters is too small, causing the NUL-terminator to be missing.
printf then prints your string character by character until it sees the NUL-terminator. In case its missing, printf just continues reading the memory until it hits the first 0x00-byte. In this case you are lucky because you are using a structure. Structures are written in one block of memory so printf just drops into the next field.
You solve your problem simply by ensuring that the arrays sizes in the structure are always larger then the character sequences you want to copy in.
I am trying to copy certain parts of a string into other, new strings, but when i try to do it and print the results it gives me weird output.. I really hope someone can help. I have a feeling that it is something about missing pointers.. Here is my source;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void getData(char code[], char ware[], char prod[], char qual[])
{
printf("Bar code: %s\n", code);
/* Copy warehouse name from barcode */
strncpy(ware, &code[0], 3);
ware[4] = "\0";
strncpy(prod, &code[3], 4);
prod[5] = "\0";
strncpy(qual, &code[7], 3);
qual[4] = "\0";
}
int main(){
/* allocate and initialize strings */
char barcode[] = "ATL1203S14";
char warehouse[4];
char product[5];
char qualifier[4];
getData(&barcode, &warehouse, &product, &qualifier);
/* print it */
printf("Warehouse: %s\nID: %s\nQualifier: %s", warehouse, product, qualifier);
return 0;
}
EDIT:
The wierd output is:
Bar code: ATL1203S14
Warehouse: ATL
ID: ♫203(♫>
Qualifier: S14u♫203(♫>
I think you meant '\0' instead of "\0" and 3 instead of 4:
ware[4] = "\0";
Try:
ware[3] = 0;
Also the & in getData(&barcode, &warehouse...) are useless. Just use getData(barcode, warehouse...);.
You're writing past the end of the chars in your getData() function. You've defined char product[5], which allocates 5 bytes of memory. That gives you array indexes 0,1,2,3,4. In getData, you write the product's null terminator to index 5, which is past the end of product, and will overwrite the next var's first character.
The same applies for barecode, warehouse, and qualifier.
Arrays in C and C++ are zero-based. The last index is one less than the length. You're setting a value in the memory after the array, for each of the arrays ware, prod and qual.
For example, instead of
char warehouse[4];
ware[4] = "\0";
you'd want:
char warehouse[4];
ware[3] = "\0";
getData(&barcode, &warehouse, &product, &qualifier);
This is not the way you should call getData. getData takes pointers, arrays are automatically converted to pointers, so theres no need to use the address-of operator &.
You should use
getData(barcode, warehouse, product, qualifier);
The sizes of the strings inside main() don't include a place for the sentinel.
You need to have:
char warehouse[5];
char product[6];
char qualifier[5];
Also, You are assigning a pointer to the string "\0" into a character, where you should be assigning the character '\0' itself.
I think I'd do things a bit differently. In particular, strncpy is almost never really useful (I'm reasonably certain it was invented for file names in the original Unix FS, and while it fits their specific requirements quite nicely, those requirements are sufficiently unusual that it's rarely good for much of anything else).
Instead, I'd use sscanf: sscanf(code, "%4c%5c%4c", ware, prod, qual);
Your question does not make it clear whether this is really correct. As others have pointed out, you're writing past the ends of the space you've allocated. Above, I've assumed you specified the number of characters you want to copy, so you'd have to expand each of the allocations by one character to make room for the terminator. Alternative, if you've already left room for the terminator and want one fewer character copied, you'd have to reduce each of the lengths above by one so the format string would be "%3c%4c%3c".