================================================================
typedef struct {
union {
struct {
char fn[5];
char ln[5];
} fullname;
char name[5+5+1];
}
unsigned int age;
unsigned int area_code;
} my_struct;
The above is a struct that I have no control over. I personally am not a fan, but the struct is "legal".
================================================================
My code:
void caller {
my_struct str;
str = (my_struct){}; //initialise
fill(&str);
printf("%s [%s/%s]\n", str.name, str.fullname.fn, str.fullname.ln); // PROBLEM!
}
void fill(my_struct * str) {
//first name
printf("Enter first name: ");
fgets(str.fullname.fn, sizeof(str.fullname.fn), stdin);
if (str.fullname.fn[strlen(str.fullname.fn) - 1] == '\n')
str.fullname.fn[strlen(str.fullname.fn) - 1] = '\0';
//last name
printf("Enter last name: ");
fgets(str.fullname.ln, sizeof(str.fullname.fn), stdin);
if (str.fullname.ln[strlen(str.fullname.ln) - 1] == '\n')
str.fullname.ln[strlen(str.fullname.ln) - 1] = '\0';
sprintf(str.name, "%s %s", str.fullname.fn, str.fullname.ln);
printf("Age: ");
scanf("%ud", &str.age);
getchar();
printf("Area Code: ");
scanf("%ud", &str.area_code);
getchar();
}
================================================================
If the input was:
joe
moe
18
214
The printout at // PROBLEM is:
joe moe [joe moe/oe]
instead of
joe moe [joe/moe]
Any ideas? I cannot, for the life of me, figure out why the values of fn and ln are changing...
The problem is that name and fullname share the memory (because of the union). So
sprintf(str.name, "%s %s", str.fullname.fn, str.fullname.ln);
also writes over fn and ln.
Not a bad question, but I don't really see how to cleanly solve this. The way I'd do it: get rid of the sprintf above, and do it on your own.
void caller
{
fill(&str);
printf("%s %s [%s/%s]\n", str.fullname.fn, str.fullname.ln, str.fullname.fn, str.fullname.ln);
}
the problem is here:
sprintf(str.name, "%s %s", str.fullname.fn, str.fullname.ln);
sprintf can't operate on overlapping memory regions.
What you can do is to NOT put a \0 after the first name, but a space instead of the \n and just print str.name.
Also, initialize the array with ' ' (spaces) it would make inputs for the 1st name that are less than 5 chars.
memset(&str, ' ', sizeof(str));
The name part of the struct is a union, so it's either name or fullname, but not both at the same time. So after setting name the field fullname is invalid. The problem with unions is that you have to provide a mechanism for detecting which part of the union is actually used. I don't see anything here to decide whether name or fullname is used.
Related
Problem:
A program that will ask an input of an employee data in this format:
ID, firstname_lastname, rate, address, position
Example:
001-111, Juan_DelaCruz, 2, Nasipit Agusan del Norte, Manager
Let Salary rate be equivalent to: 1=250, 2=300, 3=350, 4=375
From the input above, it will display like this:
Employee:001-111
First Name: Juan
Last Name: Dela Cruz
Salary rate: 300
Address: Nasipit Agusan del Norte
Position: Manager
I want the salary rate to automatically display its corresponding equivalent value based on the metric set above. I'm trying to figure out how to manipulate the strings so that whatever the result from string 'rate' will be passed on to string 'sal' with its value. Any inputs will be appreciated!
#include <stdio.h>
#include <string.h>
int main () {
char *empdata[100];
char *id, *fname, *lname, *rate, *add, *posi;
printf("Employee data format: ID, firstname_lastname, rate, address, position");
printf("\nEmployee data example: 001-111, Juan_DelaCruz, 2, Nasipit Agusan del Norte, Manager");
printf("\nLet Salary rate be equivalent to: 1=250, 2=300, 3=350, 4=375");
printf("\n\nEnter your data: ");
gets(empdata[100]);
id=strtok(empdata[100], ",");
fname=strtok(NULL, "_");
lname=strtok(NULL, ",");
rate=strtok(NULL, ",");
add=strtok(NULL, ",");
posi=strtok(NULL, ",");
char sal1[5]="250", sal2[5]="300", sal3[5]="350", sal4[5]="375";
char sal[3];
if (strncmp(rate,"1", 1) == 0) {
strcpy(sal[3],sal1[5]);
} else if (strncmp(rate,"2", 1) == 0) {
strcpy(sal[3],sal2[5]);
} else if (strncmp(rate,"3", 1) == 0) {
strcpy(sal[3],sal3[5]);
} else if (strncmp(rate,"4", 1) == 0) {
strcpy(sal[3],sal4[5]);
}
printf("\n\nHere's your employee data from the input above: ");
printf("\n\nEmployee: %s", id);
printf("\nFirst Name: %s", fname);
printf("\nLast Name: %s", lname);
printf("\nSalary Rate: %s", sal[3]);
printf("\nAddress: %s", add);
printf("\nPosition: %s", posi);
return 0;
}
In the code there are 2 problems:
The strings declaration is wrong.
In C strings are made by the actual characters and \0 (\0 is the string terminator).
In your code you declarated 4 strings, each one is a char[5] meaning it can contain 5 chars (4 characters + \0), the string in which you want to copy the values is a char[3] meaning it can contain only 3 chars ( 2 characters + \0).
They arent compatible because in your scenario you are trying to copy a string of 3 characters + \0 to a string that can contain only 2 characters + \0.
For example ,from your code, sal1[5]="250" in reality is "250\0" using 4/5 chars
The correct declaration would be:
char sal1[5]="250", sal2[5]="300", sal3[5]="350", sal4[5]="375";
char sal[5];
The strcpy parameters are wrong.
In C strcpy() needs two parameters: char* destination and char* source, as you can see they both are char pointers.
The pointers have to be pointers to the first element of the string because the functions copies the string starting from the pointer you gave as parameter to the terminator \0.
In your code you wrote as parameter sal[3] and sal[5] wich are the last elements of the two strings. This leads to a lot of errors.
The right use of strcpy() in your code is:
strcpy(&sal[0],&sal1[0]);
//or
strcpy(sal,sal1);
Also, not raleted to the question, the printf at the end is wrong for the same motivation.
The correct version is:
printf("\nSalary Rate: %s", sal);
I hope my anser was useful.
Sorry if i said something wrong, i'm kind of a new user and english is not my first language.
Note the space after the comma in the sample input...
001-111, Juan_DelaCruz, 2, Nasipit Agusan del Norte, Manager
Post rate=strtok(NULL, ",");, rate contains two characters, space and '2', terminated by '\0'.
Later, when performing a strncmp you have to accommodate for this....
An example would be...
(strncmp(rate," 2", 2) == 0);
I am sure you will figure more robust implementations, as time goes by...
Here is my version, with minimal changes to the current implementation.
Please see the comments.
int main () {
//char *empdata[100]; /* declares "empdata" as array[100] of pointers to char.*/
char empdata[100]; /* declares "empdata" as array[100] of characters */
char *id, *fname, *lname, *rate, *add, *posi;
printf("Employee data format: ID, firstname_lastname, rate, address, position");
printf("\nEmployee data example: 001-111, Juan_DelaCruz, 2, Nasipit Agusan del Norte, Manager");
printf("\nLet Salary rate be equivalent to: 1=250, 2=300, 3=350, 4=375");
printf("\n\nEnter your data: ");
//gets(empdata[100]); /* the gets function was officially removed from C`s \
2011 international standard \
use fgets(char *s, int n, FILE * stream); \
fgets returns 's' or NULL if EOF or error occurs */
fgets(empdata,100,stdin);
//id=strtok(empdata[100], ","); /* strtok expects a character pointer */
id=strtok(empdata, ","); /* "empdata" is the "address of/points to" the first \
element of the array*/
//Have made similar changes to the calls to strcpy and printf
fname=strtok(NULL, "_");
lname=strtok(NULL, ",");
rate=strtok(NULL, ",");
add=strtok(NULL, ",");
posi=strtok(NULL, ",");
char sal1[5]="250", sal2[5]="300", sal3[5]="350", sal4[5]="375";
//char sal[3]; /* make sure to map the array sizes when copying \
will ensure that the '\0' terminator is copied as well */
char sal[5];
if (strncmp(rate," 1", 2) == 0) {
strcpy(sal,sal1);
} else if (strncmp(rate," 2", 2) == 0) {
strcpy(sal,sal2);
} else if (strncmp(rate," 3", 2) == 0) {
strcpy(sal,sal3);
} else if (strncmp(rate," 4", 2) == 0) {
strcpy(sal,sal4);
}
printf("\n\nHere's your employee data from the input above: ");
printf("\n\nEmployee: %s", id);
printf("\nFirst Name: %s", fname);
printf("\nLast Name: %s", lname);
printf("\nSalary Rate: %s", sal);
printf("\nAddress: %s", add);
printf("\nPosition: %s", posi);
return 0;
}
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void get_name();
void display_name(char *fullname);
int main(void)
{
char first[80];
char second[80];
char *fullname[80];
get_name();
display_name(*fullname);
system("pause");
return 0;
}
void get_name()
{
char first[80];
char second[80];
char *fullname[80];
printf("Please enter first name: ");
scanf("%s", &first);
printf("\nPlease enter last name: ");
scanf("%s", &second);
strcpy(*fullname, first);
strcat(*fullname, " ");
strcat(*fullname, second);
printf("\n\nFull name is : %s ", *fullname);
}
void display_name(char *fullname)
{
int index;
char check;
int count=0;
printf("\n\nFull name is : %s ", fullname); //check to see if string is passes correctly
for(index=0; fullname[index] != '\0'; index++)
{
check=fullname[index];
if(check != ' ')
{
count++;
}
}
printf("\n\nNumber of characters in string is: %i\n", count);
}
im trying to send the string from get_name() to display name to count the number of characters. Everytime i pass the string, its comes out as gibberish. Am i passing wrong? I need to use one function to get the first and last name and concatenate the full name, then use another function to count the number of characters.
You're using pointers and scanf quite wrongly.
First of all scanf argument to for %s is supposed to be an array of characters. Remember that the array is in fact the pointer to the array.
Second you declare fullname to be an array of 80 pointers which is probably not what you want to do. Especially when you don't allocate the space for the string.
Instead it should be something like:
void get_name()
{
char first[80];
char second[80];
char fullname[80]; // an array of chars instead of pointers
printf("Please enter first name: ");
scanf("%s", first); // not taking the address of first - is already an address
printf("\nPlease enter last name: ");
scanf("%s", second); // not taking the address of second - is already an address
strcpy(fullname, first); // don't dereference fullname
strcat(fullname, " "); // don't dereference fullname
strcat(fullname, second); // don't dereference fullname
printf("\n\nFull name is : %s ", fullname); // don't dereference fullname
}
The declarations of variables are local to the scope where they are declared.
IOW when you declare first, second and fullname in your function get_name, they are local to that function. In order to pass the value outside of the function you have two, no three ways to do this starting with the worst way:
(1) declare the variable global, i.e. outside of main then share that variable in your function(s).
(2) declare the variable in main but pass it to the function who then fills in the string
int main()
{
char fullname[80];
get_name(fullname,sizeof(fullname)); // good to tell function avail size
...
void get_name(char* fullname, size_t length)
{
...
(3) Allocate memory on the heap, heap memory can be passed around between functions via a pointer
int main()
{
char* fullname = NULL;
get_name(&fullname);
...
void get_name(char** fullname)
{
*fullname = malloc(80);
...
EDIT
In order to read strings from the keyboard it is better to use fgets()
char buffer[128];
if (fgets(buffer,sizeof(buffer),stdin) != NULL) {
// remove the \n
char* p = strchr(buffer,'\n');
if ( p != NULL ) {
*p = '\0';
}
}
Using scanf reading from the keyboard is to be avoided, if you need to extract information use instead sscanf on the string read with fgets
So as part of a school assignment I have to create an application to handle the input of various fields using a structure. defined outside of main as following
typedef struct stud {
struct number {
int studNum;
} number;
struct name {
char firstName[NAME_SIZE];
char lastName[NAME_SIZE];
} name;
struct cellNum {
int areaCode;
int prefix;
int suffix;
} cellNum;
struct courses {
struct fall {
char className[NAME_SIZE];
float mark;
} fall;
struct winter {
char className[NAME_SIZE];
float mark;
} winter;
} courses;
} stud;
NAME_SIZE is defined as 30
I access the struct as following
stud studArray[100]; // max 100 students
stud *studPtr;
for (int i = 0; i < studCount; i++) {
studPtr = &studArray[i];
initializeStrings(studPtr[i]);
getNum(studPtr[i]);
getName(studPtr[i]);
getCell(studPtr[i]);
getCourses(studPtr[i]);
}
initializeStrings is where I add the null terminator's
void initializeStrings(stud student) {
student.name.firstName[NAME_SIZE - 1] = '\0';
student.name.lastName[NAME_SIZE -1] = '\0';
student.courses.fall.className[NAME_SIZE -1] = '\0';
student.courses.winter.className[NAME_SIZE -1] = '\0';
}
This is now where the problem occurs: in any of my various functions, when I try and access any of the information I write to my string, I get an output of garbage characters that look like a sideways T, but only if i access the data in a different function.
Example: this is the code to get 2 courses and marks
void getCourses(stud student) {
getchar();
printf("\n%s", "Enter Course name - Fall 2016: ");
fgets(student.courses.fall.className, NAME_SIZE - 1, stdin);
fflush(stdin); // suggested by my prof to fix the issue, did nothing
printf("\n%s%s%s", "Enter mark received for ", student.courses.fall.className, ": ");
scanf("%f", &student.courses.fall.mark);
getchar();
printf("\n%s", "Enter Course name - Winter 2017: ");
fgets(student.courses.winter.className, NAME_SIZE - 1, stdin);
printf("\n%s%s%s", "Enter mark received for ", student.courses.winter.className, ": ");
scanf("%f", &student.courses.winter.mark);
}
If I enter helloWorld as a course name, the system correctly prints
enter mark received for helloWorld
but when I try and print the data from my print function:
void printData(stud student) {
// various other values (none of which work)
printf("\t%s\t%s\t%f\n", "Fall2016", student.courses.fall.className, student.courses.fall.mark);
}
I get garbage data output ( image )
Any help/code criticism welcome
EDIT: Thank you Eddiem, and everyone else, you pointed me in the right direction.
This code doesn't really make sense. First, why not pass stud* pointers to each of the functions you're calling below? Regardless, the way you have it here, you're initializing studPtr to point to a particular element in the studArray array, but then still indexing i into that pointer. You could probably pass studPtr[0], but that's just weird.
Original code:
stud studArray[100]; // max 100 students
stud *studPtr;
for (int i = 0; i < studCount; i++) {
studPtr = &studArray[i];
initializeStrings(studPtr[i]);
getNum(studPtr[i]);
getName(studPtr[i]);
getCell(studPtr[i]);
getCourses(studPtr[i]);
}
I would suggest modifications like the following:
void initializeStrings(stud *student) {
student->name.firstName[NAME_SIZE - 1] = '\0';
student->name.lastName[NAME_SIZE -1] = '\0';
student->courses.fall.className[NAME_SIZE -1] = '\0';
student->courses.winter.className[NAME_SIZE -1] = '\0';
}
These modifications would need to be made to each if the functions that currently take a stud parameter. Then, change your loop initialization to:
for (int i = 0; i < studCount; i++) {
initializeStrings(&studArray[i]);
getNum(&studArray[i]);
getName(&studArray[i]);
getCell(&studArray[i]);
getCourses(&studArray[i]);
}
This is not right:
studPtr = &studArray[i];
initializeStrings(studPtr[i]);
Say you want to access the third element of your array, so i is 3. This gives you an offset to that third entry:
studPtr = &studArray[i];
Now you use an index with that....
initializeStrings(studPtr[i]);
So you're accessing 3 elements further than the third one you're already at; i.e. element 6. You can see you're going to step off the end of the array, or access elements you haven't initialised.
So use either:
studPtr = &studArray[i];
initializeStrings(studPtr);
or
initializeStrings(&studArray[i]);
Those two amount to the same thing, and point at the same place.
The problem is you're not passing by reference (aka using pointers). If you don't use pointers then functions like getCourses modify temporary data instead of the data directly. Thus, the junk values in the original data are never removed.
Change
void getCourses(stud student) { // no pointer = copy data to temporary memory, original data is unmodified in this function.
getchar();
printf("\n%s", "Enter Course name - Fall 2016: ");
fgets(student.courses.fall.className, NAME_SIZE - 1, stdin);
fflush(stdin); // suggested by my prof to fix the issue, did nothing
printf("\n%s%s%s", "Enter mark received for ", student.courses.fall.className, ": ");
scanf("%f", &student.courses.fall.mark);
getchar();
printf("\n%s", "Enter Course name - Winter 2017: ");
fgets(student.courses.winter.className, NAME_SIZE - 1, stdin);
printf("\n%s%s%s", "Enter mark received for ", student.courses.winter.className, ": ");
scanf("%f", &student.courses.winter.mark);
}
To
void getCourses(stud *student) { // notice the pointer used. Original data is to be modified.
getchar();
printf("\n%s", "Enter Course name - Fall 2016: ");
fgets(student->courses.fall.className, NAME_SIZE - 1, stdin);
fflush(stdin); // suggested by my prof to fix the issue, did nothing
printf("\n%s%s%s", "Enter mark received for ", student.courses.fall.className, ": ");
scanf("%f", &student->courses.fall.mark);
getchar();
printf("\n%s", "Enter Course name - Winter 2017: ");
fgets(student->courses.winter.className, NAME_SIZE - 1, stdin);
printf("\n%s%s%s", "Enter mark received for ", student.courses.winter.className, ": ");
scanf("%f", &student->courses.winter.mark);
}
Further more, you must modify your for loop to handle the pointers. Ie, change getCourses(studPtr[i]); to getCourses(&studPtr[i]);
I am trying to learn to program in C but am having trouble with manipulating strings as C treats strings as arrays.
My aim was to make a program that stores the users first name and surname.
Here is my progress:
#include <stdio.h>
int main(int argc, const char * argv[]) {
//defining the variables
char first_name[100];
char surname[100];
char ch[2];
// Asking for the first name and storing it
printf("What's your first name?\n");
scanf("%s", first_name);
// Prints the first name
printf("Hey %s!\n",first_name);
//Asks the user if they want to store their surname
printf("Would you like to tell me your second name? This is optional so type 'Y' for yes and 'N' for no.\n");
scanf("%s", ch);
//validate if they want to store it or not
if (ch == "Y"){
printf("What is your surname?\n");
scanf("%s", surname);
printf("Your whole name is %s %s", first_name, surname);
}
return (0);
}
However, with this code, I get an error because my IDE(xCode) tells me to use the strcmp function. I then edited the code to become this:
if (strcmp(ch, "Y")){
printf("What is your surname?\n");
scanf("%s", surname);
printf("Your whole name is %s %s", first_name, surname);
}
However variable ch is not a literal and so is not comparable.
Sidenote
I did try to compare two literals too, just to see how it works:
char *hello = "Hello";
char *Bye = "Bye";
if (strcmp(hello, Bye)){
printf("What is your surname?\n");
scanf("%s", surname);
printf("Your whole name is %s %s", first_name, surname);
}
But even this gave an error:
Implicitly declaring library function 'strcmp' with type 'int (const *char, const *char)'
I believe I am not able to do this due to my lack of experience so it would be much appreciated if you could help me understand what I'm doing wrong and how I can fix the problem.
You need to include the appropriate header:
#include <string.h>
Also note that your desired logic probably calls for:
if (!strcmp(hello, Bye))
Instead of:
if (strcmp(hello, Bye))
Since strcmp returns 0 in case of equality.
There are several issues you should correct concerning how you handle input with scanf. First always, always validate the number of successful conversions you expect by checking the return for scanf. Next, as mentioned in the comment, there is NO need to include <string.h> in your code to make a one-letter comparison. Use a character comparison instead of a string comparison. Lastly, always limit your input to the number of characters available (plus the nul-terminating character.
Putting the bits together, you could do something like the following:
#include <stdio.h>
#define MAXN 100
int main (void) {
char first_name[MAXN] = "", surname[MAXN] = "";
int ch;
printf ("What's your first name?: ");
if (scanf ("%99[^\n]%*c", first_name) != 1) {
fprintf (stderr, "error: invalid input - first name.\n");
return 1;
}
printf ("Hey %s!\n", first_name);
printf("Enter surname name? optional (Y/N) ");
if (scanf("%c%*c", (char *)&ch) != 1) {
fprintf (stderr, "error: invalid input - Y/N\n");
return 1;
}
if (ch != 'y' && ch != 'Y') /* handle upper/lower case response */
return 1;
printf ("Enter your surname?: ");
if (scanf (" %99[^\n]%*c", surname) != 1) {
fprintf (stderr, "error: invalid input - surname\n");
return 1;
}
printf ("\nYour whole name is : %s %s\n", first_name, surname);
return 0;
}
Example Use/Output
$ ./bin/firstlast
What's your first name?: David
Hey David!
Enter surname name? optional (Y/N) Y
Enter your surname?: Rankin
Your whole name is : David Rankin
Look it over and let me know if you have any questions.
There are two problems here. Firstly you need to see what value is returned by the strcmp and secondly you must use the approprate hedder.
You must use:
#include <string.h>
Secondly, you must edit your if-else statement so it is like this:
if (strcmp(ch, "Y") == 0){
printf("What is your surname?\n");
scanf("%s", surname);
printf("Your whole name is %s %s", first_name, surname);
}
We do this because the strcmp function returns a negative value if ch is smaller than "Y", or a positive value if it is greater than "Y" and 0 if both strings are equal.
I want to take the first letter from my firstname string variable and add it to the second letter of the lastname variable.
My program so far is:
#include <stdio.h>
main() {
char firstname [256];
char lastname [256];
printf("What's your first name?: ");
scanf("%c",&firstname);
printf("What is your last name? ");
scanf("%s",&lastname);
printf("\nYour school.edu e-mail address is: %c%s2#school.edu",firstname,lastname);
return 0;
}
However, I would like for my code to take the first initial (the first letter of the first name) and store it into the firstname variable.
As strings are array of characters, you need to take the first element from the array:
char firstname_initial;
firstname_initial = firstname[0]
Also note that since lastname and firstname are buffers, you don't need to pass a pointer to them in scanf:
scanf( "%s", firstname );
scanf( "%s", lastname );
And one last thing - scanf is a dangerous function and you should not use it.
Suppose the user types:
Michael
in response to the first prompt. The %c format reads the M; the %s format reads ichael without bothering to get any new data.
Also, you should not be passing &firstname or &lastname; you should be passing just firstname and lastname to scanf(). The difference is in the type; with the ampersand, you're passing a char (*)[256] which is not the same as the char * that scanf() expects. You get away with it, but 'get away with it' is the operative term.
Use a %s format (or, better, %255s format) for the two scanf() calls. Then pass firstname[0] and lastname to printf(). You might want to think about using tolower() from <ctype.h> on the first letter, and maybe on the last name too.
This is a reasonable approximation to a good program:
#include <stdio.h>
int main(void)
{
char firstname[256];
char lastname[256];
printf("What's your first name? ");
if (scanf("%255s", firstname) != 1)
return 1;
printf("What's your last name? ");
if (scanf("%255s", lastname) != 1)
return 1;
printf("Your school.edu e-mail address is: %c%s2#school.edu\n",
firstname[0], lastname);
return 0;
}
It avoids quite a lot of problems, one way or another. It is not completely foolproof, but most people won't run into problems with it.
I think you want the variable firstname to store only the initial.
So that firstname act like string.
firstname[1] = '\0'; //mark the end of string on second character
printf("\nYour school.edu e-mail address is: %s%s2#school.edu",firstname,lastname);
#include <stdio.h>
#include<string.h>
main() {
char firstname [256];
char lastname [256];
char str [50];
printf("What's your first name?: ");
scanf("%s",firstname);
printf("What is your last name? ");
scanf("%s",lastname);
str = strcpy(str, firstname[0]);
str = strcpy(str,lastname[1]);
printf("\nYour school.edu e-mail address is: %s2#school.edu",str);
return 0;
}
Copy first char from c string
char extractedchar = '0';
extractedchar=myoldstring[0];
Note : the char '0' is there just to test later in the application
Assuming expected input:
fname = Batman
lname = Joker
Expected Output:
Your school.edu e-mail address is: BJBker2#school.edu
Try this:
void main( void )
{
char fname = 0;
char lname[256] = {0};
printf("Enter firstname\n");
scanf("%c", &fname);
printf("Enter lastname\n");
scanf("%s", lname);
lname[1] = fname;
printf("Your school.edu e-mail address is: %c%s2#school.edu\n", fname, lname);
return;
}