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.
Related
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.
My program needs these functionalities:
NOTE: I did not include the codes for the numbers 1,2 & 4 since I already finished them. The 3rd one is my problem.
The program should continuously allow input from the user as long the user still wants to. (Dynamically)
Get the final grade of a student (average of frst_grade, scnd_grade, fnl_grade)
Get the number of students per college.
Get student name by inputting s_id.
My problem is how to compare the search input to the user input in s_college to get the number of students. The only way I know is by using strcmp() but it gives me this error: invalid conversion from 'char' to 'const char*' [-fpermissive]
So how do I compare these two to get the number of students per college?
#include<stdio.h>
#include<string.h>
#include<conio.h>
int i,n,sum,search,num=0,ctr=0;
char answer,choice,choice2,search2;
struct record{
int s_id;
char s_name[100];
char s_course;
char s_college[5];
int s_scoress;
}id[100],name[100],course,college[100],scores;
struct s_scores{
int frst_grade;
int scnd_grade;
int fnl_grade;
}first,second,final;
void ADD();
void COLLEGE();
void ID();
void COLLEGE(){
printf("Enter college (abbreviation only)");
scanf("%s",&search2);
for(i=0;i<num;i++){
if(strcmp(college[i].s_college,search2)==0);
ctr++;
}
printf("The number of students in %s is %d",search2,ctr);
Lets take a look at these (partial) lines:
char ..., search2;
...
scanf("%s",&search2);
...
...strcmp(college[i].s_college,search2)...
The variable search2 is a single character. Trying to put a string into it will write at least two character: The string you read plus the string terminator. That means you will write out of bounds.
You then use the character variable as an argument to strcmp which converts the contents of search2 into a pointer and uses that pointer as a pointer to a string.
Both of these problems will lead to undefined behavior.
Is search2 supposed to be a string? Then declare it as an array, like
char ..., search2[100];
If search2 is supposed to be a single character then first you need to read a single character
scanf("%c", &search2); // Note the changed format to read a single character
And then you need to change your comparison to not use strcmp.
You cannot use strcmp with what is not a null-terminated string. You can write
if(college[i].s_college[0] == search2 && college[i].s_college[1] == '\0')
Don't forget to remove the junk semicolon to have the if statement work.
Your search2 is just a character. You need a string
Perhaps declare search2 as follows:
char search2[50];
Also read up about scanf to prevent buffer overruns:
scanf("%49s", search2); // Do not go past the end of search2[50]
Well compiler tells you error: Variable search2 is char while s_college[5]; is array of chars. Function strcmp requires two arrays/pointers in order to work.
If search2 is only one byte then you can create: char Search2[2]; that would hold that one char and terminal null. But this would work only if search2 is one byte. If you however have to compare two array of chars where search2 is more then one byte, then you should probably think about dynamic allocation or create a static array char search2[some_length];.
this is not a complete 'answer', however, it does fix some of the major problems in the code:
Define your struct's like this;
struct s_scores
{
int frst_grade;
int scnd_grade;
int fnl_grade;
};
struct record
{
int s_id;
char s_name[100];
char s_course;
char s_college[5];
struct s_scores s_scoress;
};
struct record records[100];
Then access the individual fields similar to:
if( 1 != scanf( "%4s", records[i].s_college ) )
{
perror( "scanf for college abbreviation failed" );
exit( EXIT_FAILURE )
}
// implied else, scanf successful
// validate the college abbreviation
for( size_t j=0; j< (sizeof(collegesAbbrevationsTable)/(sizeof( *collegeAbbreviationsTable ); i++ )
{
if( strncmp( collegeAbbreviationsTable[j], records[i].s_college, 4)
{ // then found matching abbreviation
break; // exit 'validation' loop
}
}
Note: perror() found in stdio.h. exit() and EXIT_FAILURE found in stdlib.h.
Note: In C, when referencing an array, the result is a pointer to the first byte of that array, so in the call to scanf() must not use & when referencing the array s_college[].
`
declae search2 as char search2[10]; or char * search2;
Reason : string2 is a character variable and college is a null terminating char array.
Signature of stncmp id int strcmp(const char* s1, const char*s2);
So the function to properly you need to passs char* or char array(which is again a char*).
I want to copy the content of some char-arrays passed as parameters in a function to another char-arrays. So I passed these arrays as pointers (passing by reference). Then I used memcpy to copy the content of these arrays to some other arrays. But the copying-process was not too exact, although I think that I used memcpy correctly. Some characters was deleted, while some new charcters appeared. I tried then to use strcpy, so the content of these arrays was correctly copied. So I want to understand why copying process failed when using memcpy. Here is the some of my code:
struct student{
bool statusFlag;
char lastname[20];
char firstname[20];
int mNr;
};
here is the method:
struct student getData(char * lastname, char * firstname, int matNr){
struct student st;
int i;
printf("%s\n",lastname);
if(insertCounter<=size){
//get data
st.statusFlag=1;
memcpy(st.lastname,lastname,strlen(lastname));
memcpy(st.firstname,firstname,strlen(firstname));
st.mNr=matNr;
printf("%s,%s,%d\n",st.lastname,st.firstname,st.mNr);
return st;
}else if(insertCounter>size){
st.statusFlag=0;
return st;
}
When I replaced memcpy with strcpy, The copy-operation was successful:
The statement
memcpy(target,source, strlen(source))
should copy all the chars of the string. But, it will stop just short of copying the 0-byte that marks the end of the string. So what you copied won't be a string. This will be a problem if you call any string functions on the new copy (target), basicaly if you use target in any way, you will march off the end, since the end is now unmarked. Probably you will pick up some extra bytes, anything that happens to be in memory after target, worst case you program segfalts if it marches far enough without finding a 0. The function strcpy will copy the 0-byte, I usually use
snprintf(target, sizeof target, "%s", source);
Since it does not write past the end of the target buffer, and it always makes room for the 0, protecting against trouble in the next string op.
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".