Scanning from a file into an array in C - c

Trying to scan from a file into a C array but I'm getting an error. It worked for me when I was using a file with only numbers on each line like:
1.2
3.4
5.2
But now I have this file:
0001:Satriani:Joe:6:38.0
0002:Vai:Steve:1:44.5
0003:Morse:Steve:10:50.0
0004:Van Halen:Eddie:3:25.75
0005:Petrucci:John:8:42.25
0006:Beck:Jeff:3:62.0
Here is how I'm trying to scan it into an array, but I get a segmentation fault!
FILE *employeesTXT;
int empID[100];
char lastName[100];
char firstName[100];
int payGroup[100];
double hoursWorked[100];
employeesTXT = fopen("employees.txt", "r");
if (employeesTXT == NULL)
{
printf("Error: file cannot be opened.\n");
} else {
while (fscanf(employeesTXT, "%[^:]:%[^:]:%[^:]:%d:%lf\n", &empID[i], lastName[i], firstName[i], &payGroup[i], &hoursWorked[i]) != EOF)
{
i++;
}
fclose(employeesTXT);
numRecords = i;
for(i = 0; i < numRecords; i++){
printf("%d - %s - %s - %d - %.2lf\n", empID[i], lastName[i], firstName[i], payGroup[i], hoursWorked[i]);
}
}
It has to be something in this line... %[^:]:%[^:]:%[^:]:%d:%lf\n

Your argument parameters are wrong for the strings:
fscanf(employeesTXT, "%[^:]:%[^:]:%[^:]:%d:%lf\n",
&empID[i], lastName[i], firstName[i], &payGroup[i], &hoursWorked[i])
lastName and firstName are declared as an array of 100 char. You want those to be strings so you need to define them to be an array of 100 "buffers".
Try changing the declarations to:
char lastName[100][50]; /* 50 or whatever the max length you'd expect + 1 */
char firstName[100][50];
I believe that should work just like that.
You also have a different issue with empID, you're reading the value as a string and not an integer. In the format, it should be %d for integers if these are indeed integers in your input.

As pointed out, for the names you are assigning each new employees' information into an one dimensional array, thereby overwriting the previous employee's information (except the first character). This eventually leads to your error when you try to assign a long enough name to an index near the end of your array which causing it to write over the last index. You can use a two dimensional array as suggested for the names:
char lastname[number_of_employees][maximum_length_of_name];
and each lastname[i] will be a null terminated string.
But, this is what structures are made for.
// Define it before main()
struct employee_type{
int empID;
char *lastname;
char *firstname;
int paygroup;
double hoursworked;
}
// In main()
struct employee_type employees[100]; // Declare an array of employee_type structures.

Change
char lastName[100];
char firstName[100];
to
char lastName[100][100];
char firstName[100][100];
Also while reading empID[i] don't use %[^:], use %d instead.

You need to have addresses as parameters for fscanf, this won't work as parameter as it is only a character:
lastName[i]

Related

format '%s' expects argument of type '*char' but argument 2 has type 'int'

When I try to compile my program I get the warning message in the title and when I run it after scanning the names and scores it just stops. I encountered this problem a lot of times while practicing working with strings, but I haven't been able to find a solution.
#include <stdio.h>
struct students {
char name[20];
int score[20];
} student;
int main() {
int i, n;
printf("Number of students:\n");
scanf("%d", &n);
for(i=0; i<n; i++) {
printf("Name of the student:\n");
scanf("%s", &student.name[i]);
printf("Score of the student:\n");
scanf("%d", &student.score[i]);
}
for(i=0;i<n;i++) {
if(student.score[i] >= 15) {
printf("%s passed the exam\n", student.name[i]); }
else {
printf("%s failed the exam\n", student.name[i]);
}
}
return 0;
}
There are several issues:
printf("%s passed the exam\n", student.name[i]);
student.name[i] is a char but the %s format specifier wants a pointer to char.
But the actual problem is that your declaration of students is not what you need. Following structure declares one student whose name can be up to 19 characters long and having 20 scores.
struct students {
char name[20];
int score[20];
} student;
But you need 20 (or more?) students each of them having one score:
struct student {
char name[50]; // name up to 49 characters
int score; // score
} student;
struct student students[20]; // array of 20 students
Il leave the implementation of the code to the reader as an exercise.
You need to get familiar with following concepts:
arrays
structs
strings
basics of scanf and printf
All these topics are covered in your C text book.
Your code have quite a few issue.
1) student should be array ( or dynamically memory allocated).
2) scanf of string needs to be done as
scanf("%s", student[i].name)
Or
scanf("%s", &student[i].name[0])
3) Still you would have issue if string length crosses 20 byte (include nul character).
char name[20];
sets aside space for a single 20-character string, so students.name[i] refers to a single character (which gets promoted to type int in the scanf call).
To define an array of strings, you need a 2D array of char, like
char name[NUMBER_OF_STRINGS][MAX_STRING_LENGTH+1];
and you read it as
scanf( “%s”, student.name[i] ); // no & operator here
Array expressions “decay” to pointer expression under most circumstances, so you don’t need the & operator here.
Alternately, you can declare an array of pointers to char, like
char *name[NUMBER_OF_STRINGS];
and then allocate memory for each string as you read it:
char buffer[MAX_STRING_LENGTH+1];
...
scanf( “%s”, buffer );
student.name[i] = malloc( strlen( buffer ) + 1 );
if ( student.name[i] )
strcpy( student.name[i], buffer );
You just need to remember to free each student.name[i] when you’re finished.
The student name is a singular array of char and needs to be an array of character arrays.
struct students {
char name[20][40];
int score[20];
} student;
I arbitrarily assumed 40 characters per name was sufficient.
The scanf for the name needs to be changed from:
scanf("%s", &student.name[i]);
To:
scanf("%s", student.name[i]);
scanf("%s", &student.name[i]); You're addressing a single char from the string you declared. I assume you would want an individual object for every student. To do this my advice would be to define your struct like this:
typedef struct students {
char name[20];
int score;
}Student;
With this you have defined a new data type called Student. Each object of the type Student has a string called name and an int resembling the score.
After you've created this model, you can treat it as just another variable type, e.g. the following is totally valid:
Student student1, student2;
Alternatively, you could create an array of Students: Student group[20] and then have a loop fill it with data:
for(int i = 0; i < n; i++){
puts("Name of the student: ");
fgets(group[i].name, 20, stdin);
puts("Score of the student: ");
scanf("%d", &group[i].score);
}
The deal is per iteration to refer to an individual object of the array of students.
Also, I would strongly recommend to use fgets() or at least gets_s() for inputting strings. scanf() has multiple problems, some of which are that it stops input if it encounters a space, tab or a newline and most importantly it doesn't check for array bounds. Consider using a safer variant, just keep in mind that fgets() appends a '\n' before the terminating null.

Error in strcmp() when I use a structure as a parameter

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

Store string into array in c

As i know, i can create an array with item inside such as:
char *test1[3]= {"arrtest","ao", "123"};
but how can i store my input into array like code above because i only can code it as
input[10];
scanf("%s",&input) or gets(input);
and it store each char into each space.
How can i store the input "HELLO" such that it stores into input[0] but now
H to input[0],E to input[1], and so on.
You need a 2 dimensional character array to have an array of strings:
#include <stdio.h>
int main()
{
char strings[3][256];
scanf("%s %s %s", strings[0], strings[1], strings[2]);
printf("%s\n%s\n%s\n", strings[0], strings[1], strings[2]);
}
Use a 2-dimensional array char input[3][10];
or
an array of char pointers (like char *input[3];) which should be allocated memory dynamically before any value is saved at those locations.
First Case, take input values as scanf("%s", input[0]);, similarly for input[1] and input[2]. Remember you can store a string of max size 10 (including '\0' character) in each input[i].
In second case, get input the same way as above, but allocate memory to each pointer input[i] using malloc before. Here you have flexibility of size for each string.
Did not really understand what you need. But here is what I guessed.
char *a[5];//array of five pointers
for(i=0;i<5;i++)// iterate the number of pointer times in the array
{
char input[10];// a local array variable
a[i]=malloc(10*sizeof(char)); //allocate memory for each pointer in the array here
scanf("%s",input);//take the input from stdin
strcpy(a[i],input);//store the value in one of the pointer in the pointer array
}
try below code:
char *input[10];
input[0]=(char*)malloc(25);//mention the size you need..
scanf("%s",input[0]);
printf("%s",input[0]);
int main()
{
int n,j;
cin>>n;
char a[100][100];
for(int i=1;i<=n;i++){
j=1;
while(a[i][j]!=EOF){
a[i][j]=getchar();
j++;
}
}
This code inspired me on how to get my user input strings into an array. I'm new to C and to this board, my apologies if I'm not following some rules on how to post a comment. I'm trying to figure things out.
#include <stdio.h>
int main()
{
char strings[3][256];
scanf("%s %s %s", strings[0], strings[1], strings[2]);
printf("%s\n%s\n%s\n", strings[0], strings[1], strings[2]);
}

Assign value to char * from ScanF

Can someone please help me understand why when I try to print out the value of student_name, it only returns null? I'm implementing a basic hashtable in C to store the a students name, id, and 2 tests. Everything else is storing correctly, I just can't manage to save the the student_name no matter what I try. I have two structs, the hashtable itself and then record, the elements I intend to put inside of the table. The character string will never be longer than 18 characters.
int main(){
char op[1];
int stu_id[1];
int exam1[1];
int exam2[1];
char * student_name = (char*)malloc(18*sizeof(char));
struct hashtable * dictionary = malloc(sizeof(struct hashtable));
dictionary->size = 13;
dictionary->table = malloc(13*sizeof(struct record *));
if(dictionary==NULL||dictionary->table==NULL){
printf("Unable to allocate memory for the dictionary.\n");
return;
}
int i;
int s = 13;
while(i<s){
dictionary->table[i]=NULL;
i++;
}
while(scanf("%s %d %d %d %s", op, stu_id, exam1, exam2, student_name) !=EOF){
if(*op=='i'){
printf("Intializing %s\n", *student_name);
add_item(dictionary, stu_id[0], exam1[0], exam2[0], student_name);
}
free(dictionary);
free(student_name);
return 0;
}
Remember that a string always have to contain a special terminator character ('\0'). This means that a string of length one (like your op array) is actually two characters.
This means that when you read into op you are actually writing beyond the bounds of the array, leading to undefined behavior. You either need to increase the size of op (to at least two), or declare it as a single char (i.e. not an array) and use the '%c' format code to read a single character.
Also, don't declare the integer variables as arrays, use the address-of operator & when calling scanf instead:
char op;
int stu_id;
int exam1;
int exam2;
/* ... */
scanf("%c %d %d %d %s", &op, &stu_id, &exam1, &exam2, student_name)
You also should not check the return value of scanf against EOF, in case the input is not formatted correctly. Compare it agains the number of values you want scanned, five in your case.
I suppose you are allocating memory for student record inside add_item() and assigning them to the dictionary->table. From the code you have posted, you are allocation memory to hold pointers to struct student record and not for the records themselves.
You need to free memory allocated for "dictionary->table" at the end of main().

How do you pass a 2d array of strings to a function in C language?

I can't figure out how to pass radjectives (2D array of strings) to randomizeadj function.
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<ctype.h>
char randomizenouns(char[][]);
char randomizeadj(char[][]);
int main() // beginning of program.
{
int a=0, b=0;
char *answers[5]={'\0'};
char *rnouns[3][10]={'\0'};
char *radjectives[2][17]={'\0'};
char *rcolors[11]={'\0'};
radjectives[0][0]="intriguing";
// ...
radjectives[1][6]="loud";
rnouns[0][0]="puppies";
// ...
rnouns[1][9]="people";
rcolors[0]="black";
// ...
rcolors[10]="orange";
{ srand(time(NULL));
printf("\n\tProgram Paragrahs\n");
printf("\tFor this program you will answer several questions which will then be used to conjure a random story the length of a paragraph.Please Keep your answers clean.Enjoy\n");
printf("\nWhat is your name?");
scanf("%s\n",answers[0]);
printf("\nWhat is your favorite book?");
scanf("%s",answers[1]);
printf("\nWhat is your favorite color?");
scanf("%s",answers[2]);
printf("\nWhat city do you live in?");
scanf("%s",answers[3]);
printf("\nWhat car do you drive?");
scanf("%s",answers[4]);
Right here is where I get lost - I cannot figure out how to pass the radjectives array to the randomizeadj function.
printf("%s gets lost in their %s %s.\n",answers[0],randomizeadj(radjectives[a][b]),answers[1]);
printf("%s loves to play with %s %s.\n",answers[0],rcolors[(rand() %11)],randomizenouns(rnouns[a][b]);.
printf("%s lives in a(n) %s %s.\n",answers[0],randomizeadj(radjectives[a][b]),answers[3]);
printf("While living in %s %s drives a(n) %s %s.\n",answers[3],answers[0],rcolors[(rand() %11)],answers[4]);
printf("%s is a(n) %s person who likes the color %s.\n",answers[0],randomizeadj(radjectives[a][b]),answers[2]);
} // end of program
char randomizenouns(char nouns[x][y]);
{
int x=(rand() %3);
int y=(rand() %10);
char randomnoun= nouns[x][y];
return randomnoun;
}
char randomizeadj(char adjectives[x][y]);
{
int x=(rand() %2);
int y=(rand() %7);
char randomadjective= adjectives[x][y];
return randomadjective;
}
Simply
randomizeadj(radjectives);
e.g.
char *adj = randomizeadj(radjectives);
printf(adj);
At the moment things won't compile, change both the declarations and definitions of the functions to:
char *randomizenouns(char *nouns[3][10]);
char *randomizeadj(char *adjectives[2][17]);
or:
char *randomizenouns(char *nouns[][10]);
char *randomizeadj(char *adjectives[][17]);
Things I changed:
Changed char[][] (a 2D array of characters) to a 2D array or character pointers (also note that the first dimension of an array must always have a length specified).
Changed your functions to return char * rather than char (otherwise your function just returns a single character, rather than a string (but you still just return adjectives[x][y]).
Other things I changed:
Changed answers to not be an array of char pointers but rather a 2D array of chars, otherwise the compiler won't have memory assigned for the values you're trying to read in.
char answers[5][100];
There's also a ; where there shouldn't be here: (for both functions)
char randomizeadj(char adjectives[x][y]);
{
...
Test program.
you can simply pass it the way you have declared:
change your function definition and declaration to following:
char *randomizenouns(char *nouns[rows][cols])
char *randomizeadj(char *adjectives[rows][cols])
Note: for 2D array you need to pass cols size, so pass as required
EDIT
and in your code you have put semi-colon( ; ) in function defintion
char randomizeadj(char adjectives[x][y]); { ... }
char randomizenouns(char nouns[x][y]); { .... }
remove semi-colon from function definition
you were getting that incompatible pointer type error as earlier on you might not have changed the function declaration signatures with the matching function definition signatures.

Resources