C language structure is not woking properly in my code - c

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).

Related

Count the amount of occurrences of a character in a string: how can I interpret this code?

The assignment asks to print out the number of times a chosen character appears in an input (no length limit) string. I wanted to solve it by only using do or do-while loops, and after a bit of googling I found this code (source: https://www.tutorialgateway.org/c-program-to-count-all-occurrence-of-a-character-in-a-string/.).
I get the gist of it, but there are many things I still haven't covered, such as the meaning of str[i], the meaning of the variable ch, and kind of how the structure works. How can I interpret it piece by piece? Or if there's any simpler way, how can I work on it? I'm a beginner and I fear this is much easier than expected but I don't have the base to move on, thank you
#include <stdio.h>
#include <string.h>
int main() {
char str[10], ch;
int i, Count;
i = Count = 0;
printf("\n Please Enter any String : ");
gets(str);
printf("\n Please Enter the Character that you want to Search for : ");
scanf("%c", &ch);
while (str[i] != '\0') {
if (str[i] == ch) {
Count++;
}
i++;
}
printf("\n The Total Number of times '%c' has Occurred = %d ", ch, Count);
return 0;
}
Well i am giving an easy example regarding that problem with a proper explanation. Hope you might understand.
char is a datatype which will accepts character type of variable. Here str[100] will be an array of length 100, where we will store our search example. ch is a character type variable where we will store the character for which we will find the concurrence.
i and count are integer variables where i will be loop variable and the count will keep count of the concurrence.
after taking the text string using puts function we are storing it in the str[100] array.
then we are taking the search letter and stored it in ch.
we are now running for loop from 0 to the length of the string we have given.
strlen() function returning us the length.
now str[i] will search from i=0 to the length size of the string. each time loop will go forward one by one letter and compare the letter with the letter inside ch.
if match found then we will increase the count value.
after the ending of the loop count will be the result of the concurrency.
reference: Concurrency of a letter in a string
#include <stdio.h>
#include <string.h>
int main()
{
char str[100], ch;
int i, Count;
Count = 0;
printf("\n Please Enter any String : ");
gets(str);
printf("\n Please Enter the Character that you want to Search for : ");
scanf("%c", &ch);
for(i = 0; i <= strlen(str); i++)
{
if(str[i] == ch)
{
Count++;
}
}
printf("\n The Total Number of times '%c' has Occured = %d ", ch, Count);
return 0;
}
The code has the following parts:
1)The header files: These contain predefined functions like scanf() which you use in your program
2)The main function: Here you are performing your character count. Usually, this function contains the driver code for the program
ch is a variable for the character you want to count in your string. You are taking this as input from the user using scanf()
str is the string you are performing your count operation in. It is also taken as input.
str[i] is used to denote the index i in the string. For example in "test", the index of 's' will be 2 as it is the 3rd character and your index starts from 0.
Final note: I recommend going through the basic syntax and usage of arrays if you do not know indexing. Also, as someone commented, do not use gets(). It causes security issues in programs as user can access stack values by giving malicious inputs containing format specifiers.
Instead, use a scanf with proper format specifiers or use fgets() when accessing content from files.

Getting an output with %s but %c is returning garbage value

I wanted to accept the details of students(name,roll no. and marks) and print the same as output.The program is going fine if i accept the name as a string but i face problem when i accept the student's name as a character.
Here's the code:
#include<stdio.h>
int main()
{
struct student
{
char name;
int rn;
float marks;
};
struct student s[2];
int i;
printf("Enter student's name,roll no. and marks:\n");
for(i=1;i<=2;i++)
{
printf("%d ",i);
scanf("%c %d %f",&s[i].name,&s[i].rn,&s[i].marks);
}
printf("Student's name,roll no. and marks are:\n");
for(i=1;i<=2;i++)
printf("\nname=%c\trn=%d\tmarks=%0.2f\n\n",s[i].name,s[i].rn,s[i].marks);
}
Information of student 1 is completely correct.But facing problem in output of student 2.I just want to know what's actually happening in case of student 2.
Change this:
for(i=1;i<=2;i++)
to this:
for(i=0; i < 2; i++)
since indexing starts from 0 to the size of your array, minus 1.
i face problem when i accept the student's name as a character ? Thats because scanf() is line buffered i.e when you enter one char and then you press ENTER key, that is also one valid char so you are giving two char as a input. To avoid this buffering problem give the whitespace before %c. for e.g
for(i = 0;i < 2;i++) { /* also you had s[2] means, you should start from i = 0 */
scanf(" %c%d%f",&s[i].name,&s[i].rn,&s[i].marks);
}
The main problem is for(i=1;i<=2;i++) as you are starting from s[1] and expecting to store into s[2] also but there is no s[2] as you declared
struct student s[2]; that means s[0] & s[1], solution is start from i = 0.
Struct is a value type and it holds single memory block on stack. So 1 char holds (depending on system) 1 character like 'M'. In order to keep name you need a pointer or array of characters. This way you are storing only 1 character and after that one some random memory junk occurs because you are referencing out of bounds value which is in this case just 1 character.

Arrays of strings, and printing those elements

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.

How to add a string to a 2D array in C

i am starting to learn C and I have ran into the problem of adding a string input to a 2D array, i am able to get the string input correctly but when i try and add the string element to the array it is not working as expected.When printing the array(which is how i test the program) it will assign each index in the array a single character instead of the entire string.
And here is my code for viewing, thank you very much in advance i appreciate any help that is posted.
#include <stdio.h>
main()
{
char c_array[3][3];
int x;
int y;
int z=10;
int i_user_input;
char c_name[256];
for(x=0;x<=+2;x++)
{
for(y=0;y<=2;y++)
{
printf("\nPlease enter a name to the system:");
scanf(" %s",&c_array[x][y]);
printf("The string is %s\n",c_name);
printf("Please press '1' if you would like to keep entering names\n");
printf("Please press '2' if you would like to print the list of names:");
scanf("%d",&i_user_input);
if(i_user_input==1)
continue;
if(i_user_input==2)
for(x=0;x<=2;x++)
{
for(y=0;y<=2;y++)
{
printf("c_array[%d][%d]=%c\n",x,y,c_array[x][y]);
}
}
}
}
}
The output looks as follows with the sample input 'Penelope!'
c_array[0][0]=P
c_array[0][1]=e
c_array[0][2]=n
c_array[1][0]=e
c_array[1][1]=l
c_array[1][2]=o
c_array[2][0]=p
c_array[2][1]=e
c_array[2][2]=!
When you declare:
char c_array[3][3];
This means that each element of your 2D array is a "char" (a single character); not a "string of characters".
To have each element be a string of characters, you need to declare your array in the following way:
char string_array[3][3][256];
I am not sure this is what you want to do though. Mw feeling is that you want an array of 3 elements where each element is a string. In that case, [3] is hardly enough, your strings will have to be less than two characters (the third being reserved for the terminating zero).
Strings aren't a type. They're a value pattern, like if you say an int stores a multiple of ten, then it ends in 0... If you say an array of char stores a string, then it ends at the first '\0', see? We can store multiples of ten in different kinds of integer variables, and likewise for strings.
Strings are patterns of values, not types. When choosing which integer type we want to use, we consider the range for integers. We choose int for small integer values (less than 32768), long for larger values (less than 2147483648) or long long for values larger than that. As a result, we choose the correct type of integer depending on the multiple of ten we expect. Likewise for strings, we need to make sure we have enough memory for the characters in the string followed by the '\0' at the end.
The character &c_array[x][y] only has enough memory for 0 characters followed by a '\0' at the end; it's only useful for storing an empty string. Perhaps you meant to declare c_array like this:
char c_array[3][3][256];
In this case, scanf expects %s to correspond to an argument of the type char *... but as your compiler will probably warn you, &c_array[x][y] will have the type char (*)[256]. If you want to fix that warning, you'll need to remove the & from your scanf code:
if (scanf("%s", c_array[x][y]) != 1) {
/* XXX: Handle an error here, *
* e.g. by exiting or returning or something */
}
While we're on that topic, you'll notice that I removed the redundant space; %s already performs the functionality that the format directive would perform. I also wrote code to check the return value of scanf, as you should...
Remember how we spoke about choosing the types of integers that we use to store data? One other consideration is whether or not the data we intend to store can be negative. Consider this: In your code, should x and y be able to store negative values? What sense does a negative array index make? It is advisable that all array indexes be declared as size_t. When you use printf to print a size_t value, you'll want to use the %zu format specifier rather than %d.
char c_name[256];
/* ... */
printf("The string is %s\n",c_name);
Now, if the string is stored into c_array[x][y], then what is the point of c_name? That's an unnecessary variable. Use c_array[x][y], instead.
printf("\nPlease enter a name to the system:");
Common implementations will often refrain from printing characters until a '\n' is written; the line is printed all at once rather than character by character. As a result, you might see some strange behaviour such as this line not appearing at the right time. Fix this problem by putting the '\n' on the end of the line, rather than the beginning:
printf("Please enter a name to the system:\n");
... or use puts, which adds a '\n' for you automatically:
puts("Please enter a name to the system:");
... or use fflush, which will write all pending unwritten data even if there is no '\n':
fflush(stdout);
In your code
scanf(" %s",&c_array[x][y]);
printf("The string is %s\n",c_name);
both the statements are wrong.
%s expects a pointer to an array, not a single char. To scan a single char, you need %c format specifier.
c_name, as used in the printf() is uninitialised. Using uninitialised value invokes undefined behaviour.
Solution: To take input element by element, you can do do something like
for(x=0; x<=2 ;x++)
{
printf("Start entering the name, one character at a time\n");
for(y=0; y< 2; y++) //note only '<' here
{
scanf(" %c", &c_array[x][y]); // note the leading space
}
c_array[x][y] = 0; //null termination of array to be used as string
}
If you want to assign a string to each index in the array, then create the array as follows :
#include<stdio.h>
int main(void)
{
char a[2][10];
int i=0;
char temp[20];
for(i=0;i<2;i++)
{
scanf("%s",temp);
strcpy(a[i],temp);
}
printf("%s",a[0]);
return 0;
}
Each string that you enter will be stored in each index of the array.
#include <stdio.h>
#include <string.h>
int main(void){
char c_array[3][3];
int x;
int y;
//int z=10;//unused
int i_user_input;
char c_name[256];
printf("\nPlease enter a name to the system:");
scanf("%255s",c_name);
printf("The string is %s\n",c_name);
printf("Please press '1' if you would like to keep entering names\n");
printf("Please press '2' if you would like to print the list of names:");
scanf("%d", &i_user_input);
if(i_user_input==1)
;
else if(i_user_input==2){
memcpy(c_array, c_name, sizeof(c_array));
for(x=0;x<3;x++){
for(y=0;y<3;y++){
printf("c_array[%d][%d]=%c\n", x, y, c_array[x][y]);
}
}
}
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 3
int main(void){
char *c_array[SIZE][SIZE] = { NULL };
int x;
int y;
//int z=10;//unused
int i_user_input;
char c_name[256];
for(x=0;x<SIZE;x++){
for(y=0;y<SIZE;y++){
printf("\nPlease enter a name to the system:");
scanf("%255s", c_name);
printf("The string is %s\n", c_name);
printf("Please press '1' if you would like to keep entering names\n");
printf("Please press '2' if you would like to print the list of names:");
scanf("%d", &i_user_input);
c_array[x][y] = strdup(c_name);
if(i_user_input==1){
continue;
}
if(i_user_input==2){
int x, y;//local variable
for(x=0;x<SIZE;x++){
for(y=0;y<SIZE;y++){
if(c_array[x][y] != NULL)
printf("c_array[%d][%d]=%s\n", x, y, c_array[x][y]);
}
}
}
}
}
for(x=0;x<SIZE;x++)
for(y=0;y<SIZE;y++)
free(c_array[x][y]);
}
Why not use pointers in you array/matrix?
#include <stdio.h>
#include <string.h>
main()
{
char *c_array[3][3];
int x;
int y;
int z=10;
int i_user_input;
char c_name[256];
for(x=0;x<=+2;x++)
{
for(y=0;y<=2;y++)
{
printf("\nPlease enter a name to the system:");
scanf(" %s",c_name);
new_string = malloc(strlen(c_name)+1)
if (new_string == NULL) {
print("error allocating string\n")
exit(-1);
}
strcpy(new_string, c_name);
c_array[x][y] = new_string
printf("The string is %s\n",c_name);
printf("Please press '1' if you would like to keep entering names\n");
printf("Please press '2' if you would like to print the list of names:");
scanf("%d",&i_user_input);
if(i_user_input==1)
continue;
if(i_user_input==2)
for(x=0;x<=2;x++)
{
for(y=0;y<=2;y++)
{
printf("c_array[%d][%d]=%c\n",x,y,c_array[x][y]);
}
}
}
}
for(x=0;x<=2;x++) {
for(y=0;y<=2;y++) {
free(c_array[x][y])
}
}
}
The code above stores the input string in each cell of the array, if that is your goal.
Note: I have no tried it, so there may be subtle errors. My point is to show you how to use pointers and their equivalence to arrays. Using C without pointers is pointless. :)

C scanf not working for multi word input

I have this code.
#include <stdio.h>
struct name
{
int age;
char fullname[20];
};
struct name names[20];
int main()
{
int n,i;
printf("Count of names:\n");
scanf("%d",&n);
for (i = 0; i < n; i++)
{
printf("Name %d : ",i);
scanf("%[^\n]s",names[i].fullname);
}
return 0;
}
And when i execute :
rupam#linux ~ $ ./a.out
Count of names:
5
Name 0 : Name 1 : Name 2 : Name 3 : Name 4 :
rupam#linux ~ $
It don't wait for user input. Somehow the scanf is not working.
Well, if i use
scanf("%s",names[i].fullname);
It works for single word inputs.
What am i doing wrong here ?
So lets see what happens with the input here. First, you call scanf("%d" to read an integer. Assuming you enter something like 5Enter, the scanf call will read digits and convert them to an integer. Since it finds at least one digit, it will succeed, reading that digit and leaving the \n from the Enter to be read.
Now you go into the loop, where you call scanf("%[^\n]s" which attempts to read one or more non-newline characters followed by a newline, then attempts to read an s. Since the next character of input is a newline, this immediately fails (reading nothing), but you don't check the return value of scanf, so you don't notice. You then loop attempting to read more, which will fail again.
So what you need to do is ignore the newline. The easiest way is probably to just use a space in the format, which causes scanf to read and ignore whitespace, until it finds a non-whitespace character; change your second scanf to:
scanf(" %19[^\n]", names[i].fullname);
Note some additional changes here. We got rid of the spurious s as you don't particularly want to match an s after the name. We also added a limit of 19 characters to avoid overflowing the fullname array (19 characters max + 1 for the terminating NULL byte).
Use getchar() after printf in for loop:
#include <stdio.h>
struct name
{
int age;
char fullname[20];
};
struct name names[20];
int main()
{
int n,i;
printf("Count of names:\n");
scanf("%d",&n);
for (i = 0; i < n; i++)
{
printf("Name %d : ",i);
getchar();//getchar here
scanf("%[^\n]s",names[i].fullname);
}
return 0;
}
If you may work with files with Windows line-ending in the future (redirecting files to stdin), then instead of using one getchar() as suggested by #jahan you can use
if(getchar()=='\r') getchar();
This can increase the portability of your code.

Resources