Arrays of strings, and printing those elements - c

I'm trying to create a program which will take information from 10 racers. The program will get and store the first name, last name, age, gender (m/f), and time for their race (hh:mm:ss). To do this I planned to have an array of structures containing each of the above elements for each racer. I then came across the problem of asking "Please enter the name of the first racer" because the word "first" needs to be changed to "second", "third" and so on... A loop wouldn't be able to do that. So I decided to then make an array of strings, where the first element of the array would be the word "first" and so on. So then I could use a loop to print the right word for each racer by accessing each element of the places array.
I'm not very experienced with strings, and arrays of strings, I searched online for some help and came up with the following program, it uses an array of characters with a pointer, which I dont quite understand, must be something to do with the strings. Anyways, when I run the program I get serious problems and have to re-open Visual Studio. Hoping someone can give me a hand and help clear up some mysteries about these arrays of strings and the significance of the pointer. Thanks!
#include <stdio.h>
#include <math.h>
typedef struct DATASET
{
char firstname[12], lastname[12], gender;
int age, hours, minutes, seconds;
};
#define MaxRacers 10
int main()
{
int i;
DATASET data[MaxRacers];
char *places[MaxRacers];
char place1[6] = "First";
char place2[7] = "Second";
char place3[6] = "Third";
char place4[7] = "Fourth";
char place5[6] = "Fifth";
char place6[6] = "Sixth";
char place7[8] = "Seventh";
char place8[7] = "Eighth";
char place9[6] = "Ninth";
char place10[6] = "Tenth";
places[0] = place1;
places[1] = place2;
places[2] = place3;
places[3] = place4;
places[4] - place5;
places[5] = place6;
places[6] = place7;
places[7] = place8;
places[8] = place9;
places[9] = place10;
printf("%s", places[1]); // TEST which works fine
for(i = 0, i < MaxRacers; i = i + 1;)
{
printf("Enter the name of the %s finisher\n", places[i]); // Problem
}
getchar();
return(0);
}
Now Ive got things going a bit further, Im running into a problem now as soon as I have finished entering the last name of the first finisher the program exits out of the command window and a new window comes up saying:
"Exception thrown at 0x0FF6D0F1 (ucrtbased.dll) in ConsoleApplication30.exe: 0xC0000005: Access violation writing location 0xFFFFFFCC.
If there is a handler for this exception, the program may be safely continued."
#include <stdio.h>
#include <math.h>
struct DATASET
{
char firstname[12], lastname[12], gender;
int age, hours, minutes, seconds;
};
#define MaxRacers 10
int main()
{
int i;
DATASET data[MaxRacers];
char *places[] = { "First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Seventh", "Eighth", "Ninth", "Tenth" };
for (i = 0; i < MaxRacers; i++)
{
printf("Enter the first name of the %s finisher:\n", places[i]);
scanf("%s", data[i].firstname);
printf("Enter the last name of the %s finisher:\n", places[i]);
scanf("%s", data[i].lastname);
printf("Enter the gender of the %s finisher: [m/f]: \n", places[i]);
scanf("%c", data[i].gender);
printf("Enter the age of the %s finisher:\n", places[i]);
scanf("%d", data[i].age);
printf("Enter the time of the %s finisher: [hh:mm:ss]\n", places[i]);
scanf("%d:%d:%d", data[i].hours, data[i].minutes, data[i].seconds);
printf("\n\n");
}
getchar();
return(0);
}

for(i = 0, i < MaxRacers; i = i + 1;)
The for loop doesn't work like that. Try this:
for(i = 0; i < MaxRacers; i++)
// ^ ^
// | |
// semicolon here more idiomatic
In addition, you should use the idiomatic character array initialization:
char *places[MaxRacers] = { "First", "Second", ... };
not only because it is way easier to type than your 20 lines of places, but also because there are far less chances to miss a typo like
places[3] = place4;
places[4] - place5; // <---- whoops
places[5] = place6;
While we're at it,
typedef struct DATASET
{ // whatever
};
makes little sense. It doesn't create any typedef name, so the word typedef is useless. It is equivalent to
struct DATASET
{ // whatever
};
Because of that, this declaration
DATASET data[MaxRacers];
is invalid in C. It is valid in C++, which probably means you are using a C++ compiler. If you are learning C, make sure your source file extension is .c.

In your second iteration of this question, you report that:
Im running into a problem now as soon as I have finished entering the last name of the first finisher
I believe that this problem is due to the fact that you have incorrectly declared data[]. DATASET is a struct, not a typedef, so you need:
struct DATASET data[MaxRacers];
But this reveals a new problem. You have several issues around your calls to scanf(). First, you are failing to provide addresses to store the results of scanf() in several instances. To fix this, you need to change to:
printf("Enter the gender of the %s finisher: [m/f]: \n", places[i]);
scanf("%c", &data[i].gender);
printf("Enter the age of the %s finisher:\n", places[i]);
scanf("%d", &data[i].age);
printf("Enter the time of the %s finisher: [hh:mm:ss]\n", places[i]);
scanf("%d:%d:%d", &data[i].hours, &data[i].minutes, &data[i].seconds);
But yet another problem is now apparent. The (evil) function scanf() often leaves newlines and other characters behind, polluting the input stream for the next input function. I personally usually write a function to handle user input in the form of strings, and then use strtol() to convert the results if numeric input is desired.
The simplest thing for you to do, though, would be to simply write a function to clear the input stream before using scanf() with the %c specifier:
void clear_stream(void)
{
int ch;
while ((ch = getchar()) != '\n' && ch != EOF)
continue; // remove unwanted characters
}
Then modify your input code like this:
printf("Enter the first name of the %s finisher:\n", places[i]);
scanf("%s", data[i].firstname);
printf("Enter the last name of the %s finisher:\n", places[i]);
scanf("%s", data[i].lastname);
printf("Enter the gender of the %s finisher: [m/f]: \n", places[i]);
clear_stream();
scanf("%c", &data[i].gender);
printf("Enter the age of the %s finisher:\n", places[i]);
scanf("%d", &data[i].age);
printf("Enter the time of the %s finisher: [hh:mm:ss]\n", places[i]);
scanf("%d:%d:%d", &data[i].hours, &data[i].minutes, &data[i].seconds);
printf("\n\n");
With many format specifiers, scanf() skips over leading whitespace, including newlines. But this is not true for the %c specifier, and this means that if you enter, say a string, the newline that is left behind in the input stream will be picked up instead of the character that you want.
These changes will get your code running. But your input scheme is fragile. It doesn't check to be sure that there was input (scanf() returns the number of values that were read) and it doesn't validate values. Do you want the user to input a negative age? I would urge you to at least rethink your input code to be sure that you get the input that you want. And because scanf() is error-prone, you should really consider using fgets() or write your own input function, such as the one that I linked to earlier.

Related

After getting user inputs the last printf() is not printing at all

Struggling on my homework assignment.
After I give inputs it stops rather than doing the random array and last print if anyone can help I would appreciate it
#include <stdio.h>
#include <stdlib.h>
int main() {
char name, color;
int age;
int *poer = &age;
char *p = &name;
char *ptr = &color;
printf("What is your name?\n");
scanf(" %s", &name);
printf("How old are you??\n");
scanf(" %d", &age);
printf("What is your favorite color?\n");
scanf(" %s", &color);
char *story[5] = {"old volkswagen beetle", "singlet", "quater", "left sock",
"blackberry bold ninek"};
srand(time(0));
printf("My pal right here %s is %d years old I feel like we have been coding"
" together for a hundred years now I always wonder where the time has gone"
" One thing I have wanted to know is why they love "
"their %s %s so much I guess I might never know\n",
name, age, color, story[rand() % 5]);
return 0;
}
Plenty of errors can be caught by enabling the compiler warnings.
Here is the list of all problems with their proper solutions:
For this line:
srand(time(0));
You need to include the time.h library, otherwise, you will get an implicit definition of time() error message. Passing NULL to time() is a good practice.
As people figured out:
char name, color;
A single char-type cannot hold more than a single ASCII character. Thus, you need to formulate a sequence of characters, called character array. In C99, variable-length arrays are supported. Still, using a macro constant for defining string lengths during compile-time makes the code good. Replace it:
#define MAX_LENGTH 128 // Prefer your length
...
char name[MAX_LENGTH], color[MAX_LENGTH];
In the similar lines:
printf("What is your name?\n");
scanf(" %s", &name);
scanf() function stops reading further input after whitespace. For example, if you input: John Doe, the name will only store John, Doe becomes truncated. Also, never put an ampersand sign for a char-array in scanf().
fgets() is considered safer than this, since it accepts a limited number of characters defined in its second argument. Replace the scanf():
// ... , sizeof name, ... --- is also applicable here
if (fgets(name, MAX_LENGTH, stdin) == NULL) {
// Do something when input's invalid
}
// Input is okay
Note: The fgets() leaves a trailing newline character as soon as it stops receiving user input. To discard this, use this after its usage:
name[strcspn(name, "\n")] = 0;
After applying all these changes, you will not get any further problems.
the following code will be fine
char name[256];
char color[256];
int age;
printf("What is your name?\n");
scanf(" %s", name);
printf("How old are you??\n");
scanf(" %d", &age);
printf("What is your favorite color?\n");
scanf(" %s", color);
in your code, a char was casted to char* the variable will hold data larger than it could. the the stack was ruined
You used char for string which is wrong. You need a char array to store the strings.
Try this:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define STR_MAX 300
int main()
{
char name[STR_MAX];
char color[STR_MAX];
int age;
printf("What is your name?\n");
scanf(" %s", name);
printf("How old are you??\n");
scanf(" %d", &age);
printf("What is your favorite color?\n");
scanf(" %s", color);
char *story[5] = {"old volkswagen beetle","singlet","quater","left sock","blackberry bold ninek"};
srand(time(0));
printf("My pal right here %s is %d years old I feel like we have been coding together for a hundred years now I always wonder where the time has gone One thing I have wanted to know is why they love their %s %s so much I guess I might never know\n",name, age, color, story[rand()%5]);
return 0;
}
your program terminated abnormally because stack was ruined.
char name; //has only 1 byte space
char color; //has only 1 byte space
but these two variables was used to hold data larger than they can. then data was written to some place else which will cause the stack overflow.
code like this will be ok
char name[256];
char color[256];

C language structure is not woking properly in my code

please take a look at the code below.
#include <stdio.h>
#include <conio.h>
struct str {
char st[1];
char rule[20];
} production_rules[30];
int main () {
int n;
printf("Enter number of productions: ");
scanf("%d", &n);
printf("Enter the productions\n");
for (int i = 0; i < n; i++) {
printf("Enter the non terminal: ");
scanf("%s", production_rules[i].st);
printf("Enter the RHS of the production Rule: ");
scanf("%s", production_rules[i].rule);
}
printf("the production rules are \n");
for (int i = 0; i < n; i++) {
printf("%s -> %s\n", production_rules[i].st, production_rules[i].rule);
}
return 0;
}
I am getting the following output
Enter number of productions: 1
Enter the productions
Enter the non terminal: A
Enter the RHS of the production Rule: abc
the production rules are
Aabc -> abc
Expected Output:
Enter number of productions: 1
Enter the productions
Enter the non terminal: A
Enter the RHS of the production Rule: abc
the production rules are
A -> abc
The problem is in the last line of the output. I don't understand why the char array is being concatenated. Can some one help me with this problem
There is no issue in your struct, but just the way you use printf, as you put %s to print the element "st", whilst you should use "%c" instead.
In fact, "st" is just a char[1], not a proper string, so it doesn't contain the string termination character '\0'.
As your struct is stored in memory as a buffer of consecutive char, the "%s" makes the "printf" stop when the termination string character is found, so at the end of the element "rule", and that's reason of your output.
So, just replace %s with %c when printf of st and it will work. Your code should appear like this:
for (int i = 0; i < n; i++) {
printf("%c -> %s\n", production_rules[i].st, production_rules[i].rule);
}
As mentioned in the comments, the problem was: not having a sufficient number of rooms in that character array. It is because the null-terminator character is always put at the end of the string, so it requires extra space.
In the current situation, your requirement is only a single character. So, you can change it into a char in the struct definition:
struct str {
char st;
char rule[20];
} production_rules[30];
And use it this way:
scanf(" %c", &production_rules[i].st);
Notice that an extra whitespace character is given here because it is necessary. Otherwise, it would simply ignore the input from being given.
Another method to solve this issue is to increase the length of the array by one. Suppose, you need 3 numbers as char[] then you need a length of 4 (extra one).

strcmp call keeps crashing my program

I'm creating a "phonebook" program for school. Basically I have to get a user to input the names and phone numbers of their contacts into two different arrays. I got that part down, but after I have to give the user an option to search the contacts either via name or phone number and I'm running into some issues.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
int main()
{
int arraysize;
printf("How many phone numbers will you be entering: ");
scanf("%d", &arraysize);
int * phoneNumbers = malloc(arraysize);
char * names = malloc(arraysize);
for (int i = 0; i < arraysize; ++i)
{
printf("Please enter the name of person %d: ", i + 1);
scanf("%s", &names[i]);
printf("Please enter %s's phone number: ", &names[i]);
scanf("%d", &phoneNumbers[i]);
}
char * searchOption;
printf("Would you like to seach via name or phone number? ");
scanf("%s", &searchOption);
if (strcmp(searchOption, "name") == 0)
{
char * searchName;
int element;
bool stop = false;
while (stop = false)
{
searchName = NULL;
printf("\nPlease enter the name you wish to search for: ");
scanf("%s", &searchName);
for (int i = 0; i < arraysize; ++i)
{
if (strcmp(searchName, names[i]) == 0)
{
element = i;
stop = true;
break;
}
}
if (stop = false)
{
printf("\nname not found, please search again!");
}
}
}
I'm pretty sure it's crashing at the strcmp() call but I have no idea why
The problem is, in
scanf("%s", &searchOption);
you're doing it wrong.
You need to
First allocate memory to searchOption pointer (or make it an array).
pass searchOption, not &searchOption to scanf().
Same issue appears for char * searchName; also later in the code.
The crash is not directly caused by the strcmp() call.
This line is at fault:
scanf("%s", &searchOption);
First of all, there is a type mismatch. For %s you have to pass an argument of type char*, not char** as you did. To fix this, remove the take-address (&) operator.
Additionally, you need to allocate memory to scan into. The scanf function doesn't do that for you. As a quick and dirty fix, you can simply make searchOption an array. Replace its declaration with
char searchOption[100];
or such to fix this. You also want to limit the number of characters scanf() attempts to read:
scanf("%100s", searchOption);
so there can't be a buffer overflow.
An even better approach is to use fgets() instead of scanf(). The fgets() function is suited better for what you want to do. Read the manual for how to use fgets().
As Alter Mann said, the same problem occurs a second time further down. You need to repair that, too.
Also i think in strcmp you have used "name" whereas you declared it as names before.If you correct this maybe program works

Interactive, randomized program in C

My goal with this program is to incorporate the users inputs into a sort of interactive/randomized story but I'm not sure how I'm supposed to get the inputs from the users to fit between *ptrDescription, *ptrBeginning, *ptrMiddle, and *ptrEnd. Any help would be much, much appreciated!
#include <stdio.h>
#include<stdlib.h>
#include<time.h>
#include <string.h>
#include <ctype.h>
int main(void){
int i;
char name[20];
char color[20];
int age;
char sentence[1];
//array of pointers to char arrays
char *ptrDescription[]={"the painfully handsome","the one and only","who seemed much older than"};
char *ptrBeginning[]={"was blissfully ignoring","could clearly see","had no idea"};
char *ptrMiddle[]={"the huge truck","the falling meteor","the bucket of milk","the mailman","the most powerful wizard"};
char *ptrEnd[]={"that was barreling toward them.","on the horizon."};
srand(time(NULL));
printf("Enter your first name: ");
scanf("%s", &name);
printf("\nEnter your age: ");
scanf("%d", &age);
printf("\nEnter your favorite color: ");
scanf("%s", &color);
for (i = 0; i < 1; i++)
{
//strcpy(sentence,ptrDescription[rand()%3]);
//strcat(sentence," ");
//strcat(sentence,ptrBeginning[rand()%3]);
//strcat(sentence," ");
//strcat(sentence,ptrMiddle[rand()%5]);
//strcat(sentence," ");
//strcat(sentence,ptrEnd[rand()%2]);
//strcat(sentence,".");
//sentence[0]=toupper(sentence[0]);
puts(sentence);
}
getch();
return 0;
}
EDIT:
I've edited a section of my code so that directly following for (i = 0; i < 1; i++) it now looks like this:
snprintf(sentence, sizeof sentence,"%s, %s %d year old, %s %s %s %s", name, ptrDescription[rand()%3], age,ptrBeginning[rand()%3], ptrMiddle[rand()%5], ptrEnd[rand()%2]);
There are tons of strange characters after the sentence in the output, like Japanese characters and stuff. I'm not sure why they're there, though. This is what it looks like exactly:
"Enter your first name: Justin
Enter your age: 20
Justin, the arrogant 20 year old, was purposefully ignoring the most powerful wizard that was barreling toward them. 汽$0HβHζ(テフフフフフフフフフフフフフH・(DキHH広$0陏&・汽$0タHζ(テフフフフフフフフフフフフフフフH WH・ H櫛H・t9HνHテ<"
Anyone know how I can get rid of them?
If you already have a name and an age, it's just a matter of inserting them into the correct place in sentence, right? So strcat(sentence, name) would work for name. age is a little trickier since you have to format the number first, and strcat won't do it for you. One solution would be to use sprintf(buf, "%d", age), and then concatenate buf (which is a scratch char array you would have to declare).
Any time you work with strings in C, you have to be concerned about having enough space in the target buffer. Your program can run out of space during both input and output. For the output, I would get rid of sentence altogether; since you just end up writing to stdout I would printf("%s", [part]) each part as you go along. For reading, scanf supports adding a length argument to the format string.
If you use one of the *printf functions, there are 2 things you must be careful about:
The arguments you pass are correct for the format string you use
Your buffer ends up null-terminated
Your current problem is with #1 - your format string promises 7 arguments to follow, but you only supply 6. snprintf grabs a "random" 7th value from the stack, interprets it as a char pointer, and copies whatever it finds there to sentence. You could see similar problems if your format string promised a char pointer but you placed an int in a given position. In this case the format string is a constant, so a smart compiler can validate that your format string matches the subsequent parameters. You'll want to get into the habit of taking compiler warnings seriously and not ignoring them.
The second point could be an issue if your sentence ended up bigger than your sentence buffer. If there is no room for a null-terminator, one won't be applied. You can check the return value of snprintf, or you can defensively always write a 0 to the last array position.

Storing values in struct objects using c and a do-while loop

I'm trying to store a few values in a struct object and I want to repeat the prompt until the user types in "yes". I want to use a do-while loop for that. I'm already failing with the read-in of the first "last name". When I type in something, the program just stops (no error). I don't even use the do-while, since I'm not sure if it will work with my while() condition.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
struct employeelist
{
char last[6];
char first[6];
int pnumber;
int salary;
};
int main()
{
struct employeelist employee[5];
char check;
//do
//{
printf("Hello. Please type in the last name, the first name, the personal number and the salary of your employees.\n");
printf("Last name: ");
scanf("%c", employee[1].last);
printf("First name: ");
scanf("%c", employee[1].first);
printf("Personal number: ");
scanf("%d", &employee[1].pnumber);
printf("Salary: ");
scanf("%d", &employee[1].salary);
printf("You have more employess (yes/no)?: ");
scanf("%c", &check);
//}while (scanf("yes"));
return 0;
}
Use %s as your format specifier if you're trying to get a string. You might also want to limit its length to 5, since that's how much space you have for last and first. So that would be %5s. Also, 5 characters is pretty short for a name.
Another comment: arrays in C are zero-based, so employee[1] is the second employeelist in your array. If you want to do this in a loop with an incrementing index, start at 0.
Hi when you read char array you must use scanf("%s", employee[1].last); %s but not %c
What do you think this code does?
scanf("%c", ....
%c indicates that scanf should only read ONE character.
One letter is not going to get you an entire name.
You need to switch to %s for starters.
First of all the first index to work
with will be '0',not 1.
wrong identifier for string,it
should be %s.
If you just want to iterate by
asking y/n then just change the
display message from yes/no to y/n
and also change that strange while
condition to check=='y'||check=='Y'.
The code will actually not work
after 5 iterations because you
initialized only 5 structures of
that type.Why don't you add that in
the loop?

Resources