I've been working on this C programming assignment and I just can't seem to find out why it is not behaving the way I expect it to be behaving. The program is supposed to run, and there are 3 possible options for commands 0, -n, and n, where n is a positive integer.
When I execute the program, and type 0 as the command (which should create a file if one has not already been created) it just loops back to asking me to enter a command.
The commands -n and n go to the line specified by n and seeks to it. n prints line n, whereas -n prints all lines from n onward until it can no longer read from the text file.
Would greatly appreciate it if somebody could give me a hint or two and steer me in the right direction.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#define BUFSIZE 256
#define LINESIZE 1024
int write(FILE *fp);
int grade_validation(int grade);
int id_validation(char studentid[]);
int display(FILE *fp, int cmd);
int display_all(FILE *fp, int cmd);
int main(int argc, char *argv[]) {
if(argc != 2) {
perror("invalid number of args");
return 1;
} else {
FILE *fp;
if((fp = fopen(argv[1], "wb+")) == 0) {
perror("fopen");
return 1;
}
write(fp);
fclose(fp);
}
return 0;
}
int write(FILE* fp) {
int grade;
char studentid[BUFSIZE];
char input[BUFSIZE];
int cmd;
while(1) {
printf("Input 0 to append, n to view, or -n to view all records starting from n.\n");
if(!fgets(input, LINESIZE, stdin)) {
clearerr(stdin);
return 0;
}
if((sscanf(input, "%d", &cmd) == 1)) {
if(cmd == 0) {
if((id_validation(studentid)) != 1 || (grade_validation(&grade) == -1)) {
continue;
}
fprintf(fp, "%s %3d ", studentid, grade);
} else if(cmd > 0) {
display(fp, cmd);
} else if(cmd < 0) {
display_all(fp, cmd);
}
}
}
}
int grade_validation(int grade) {
char input[BUFSIZE];
FILE *fp;
if(grade >= 0 && grade <= 100) {
return 1;
}
if(sscanf(input, "%d", &grade) == 1) {
if((grade_validation(grade)) == 1) {
if(fprintf(fp, "%3d", grade) == 0) {
return 0;
}
printf("Grade recorded successfully.\n");
return 1;
}
}
return 0;
}
int id_validation(char studentid[]) {
char input[BUFSIZE];
FILE *fp;
size_t i = 0;
if(strlen(studentid) == 9) {
for(i = 0; i < 9; i++) {
if(isdigit(studentid[i])) {
return 1;
}
}
}
if(sscanf(input, "%s", studentid) == 1) {
if((id_validation(studentid)) == 1) {
if(fprintf(fp, "%s", studentid) == 0) {
return 0;
}
printf("Student ID recorded successfully.\n");
return 1;
}
}
return 0;
}
int display(FILE *fp, int cmd) {
char studentid[BUFSIZE];
int grade;
if(!fgets(cmd, BUFSIZE, fp)) {
clearerr(stdin);
return 0;
}
fseek(fp, cmd, SEEK_SET);
fprintf(stderr, "%s %3d", studentid, grade);
}
int display_all(FILE *fp, int cmd) {
char studentid[BUFSIZE];
int grade;
if(!fgets(cmd, BUFSIZE, fp)) {
clearerr(stdin);
return 0;
}
fseek(fp, cmd, SEEK_SET);
while((sscanf(studentid, grade, "%s %3d", cmd)) != EOF) {
fprintf(stderr, "%s %3d", studentid, grade);
}
}
You're trying to validate the uninitialized studentid and grade.
Also, you pass &grade to grade_validation, which expects and integer.
This would cause a warning, which should make you figure out something is wrong. Always compile with warnings enabled, and treated as errors (in gcc, -Wall -Werror).
Related
i made this code for my college lesson:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100
int palindromoR(int i, int f, char *s)
{
if (f - i <= 0)
return 1;
if (s[i] != s[f]) {
return 0;
} else {
return palindromoR(i+1, f-1, s);
}
}
void palindromo(char *s)
{
int saida = palindromoR(0, strlen(s) - 1, s);
if (saida)
{
printf("eh palindromo\n");
}
else
{
printf("nao eh palindromo\n");
}
}
void inversaR(char *str)
{
static int i=0;
int tam = strlen(str) - i;
char temp;
if (tam +1 == 0)
return;
temp = str[tam];
printf ("%c",temp);
i++;
return inversaR (str);
}
void inversa(char *s)
{
inversaR(s);
printf("\n");
}
unsigned long stirlingR(unsigned long n, unsigned long k)
{
// implemente essa função recursiva
return 0;
}
void stirling(int n, int k)
{
printf("%lu\n", stirlingR(n, k));
}
void padraoR(unsigned n)
{
}
void padrao(unsigned n)
{
padraoR(n);
printf("\n");
}
int main(int argc, char *argv[])
{
char file_name[MAX], aux[MAX];
FILE *entrada;
int t, a, b;
scanf("%s", file_name);
entrada = fopen(file_name, "r");
if (entrada == NULL)
{
printf("Nao encontrei o arquivo!");
exit(EXIT_FAILURE);
}
fscanf(entrada, "%d", &t);
if (t < 1 || t > 4)
{
printf("Parametros incorretos.\n");
printf("Ex:\n");
printf("tp01_recursao 1 [para testar palindromo]\n");
printf("tp01_recursao 2 [para testar inversa]\n");
printf("tp01_recursao 3 [para testar Stirling]\n");
printf("tp01_recursao 4 [para testar padrao]\n");
}
if (t == 1)
{
printf("\nTestando palindromo()\n\n");
fscanf(entrada, "%s", aux);
while (aux[0] != '.')
{
palindromo(aux);
fscanf(entrada, "%s", aux);
}
}
else if (t == 2)
{
printf("\nTestando inversa()\n\n");
fscanf(entrada, "%s", aux);
while (aux[0] != '.')
{
inversa(aux);
fscanf(entrada, "%s", aux);
}
}
else if (t == 3)
{
printf("\nTestando Stirling()\n\n");
fscanf(entrada, "%d %d", &a, &b);
while (a != -1)
{
stirling(a, b);
fscanf(entrada, "%d %d", &a, &b);
}
}
else if (t == 4)
{
printf("\nTestando padrao()\n\n");
fscanf(entrada, "%d", &a);
while (a != -1)
{
padrao(a);
fscanf(entrada, "%d", &a);
}
}
return 0;
}
My function inversaR seems to work when i try like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void inversaR(char *str)
{
static int i=0;
int tam = strlen(str) - i;
char temp;
if (tam +1 == 0)
return;
temp = str[tam];
printf ("%c",temp);
i++;
return inversaR (str);
}
void inversa(char *s)
{
inversaR(s);
printf("\n");
}
int main (){
char teste[100] = "alucard";
inversa(teste);
return 0;
}
the code above gives me the answer "dracula" as expected, but when trying with the first code it cuts the strings in 2 characters. The archive it's reading contains the following strings:
2
ab
gato
minerva
alucard
.
I tried to chance it using the function strrev() and it seems to work just fine, otherwise the same problem kept blowing my mind.
I tried out your code and saw the quirky chopped output you referred to. Doing some debugging of the code led me to the issue with your static variable, "i" in the recursive "inversaR" function. After each call with a different string, the value was left with an arbitrary value from the previous recursive call set which was giving either a partial string or no string at all.
With that it was apparent that when the final character had been printed and the return back up the function call stack was occurring, this variable needed to be reset. Following is a refactored version of the function.
void inversaR(char *str)
{
static int i=0;
int tam = strlen(str) - i;
char temp;
//printf("tam: %d\n", tam);
if (tam +1 == 0)
{
i = 0; /* This needs to be reset when returning up the recursive call stack */
return;
}
temp = str[tam];
printf ("%c",temp);
i++;
return inversaR (str);
}
Also, just to clarify to anyone testing this program, I added a "printf" statement prior to the prompt for a file name so that it is clear what is wanted for input.
printf("File name: "); /* Added to alert the user to enter a file name */
scanf("%s", file_name);
entrada = fopen(file_name, "r");
With those two bits of code refactored, and having created a text file with the sample string set, the following terminal output was created.
#Vera:~/C_Programs/Console/Dracula/bin/Release$ ./Dracula
File name: Test.txt
Testando inversa()
ba
otag
avrenim
dracula
All of the strings appear to have been properly reversed. Go ahead and try out these program tweaks and see if they meet the spirit of your project.
I need to load strings from file into a struct array.
CORRECT OUTPUT:
4
Sarajevo,345123
Tuzla,123456
Mostar,101010
Banja Luka,234987
MY OUTPUT:
1
Sarajevo 345123
Tuzla 123456
Mostar 101010
Banja Luka 234987,544366964
Code:
#include <stdio.h>
#include <string.h>
struct City {
char name[31];
int number_of_citizen;
};
int load(struct City cities[100], int n) {
FILE *fp = fopen("cities.txt", "r");
int i = 0;
while (fscanf(fp, "%[^,]s %d\n", cities[i].name, &cities[i].number_of_citizen)) {
i++;
if (i == n)break;
if (feof(fp))break;
}
fclose(fp);
return i;
}
int main() {
int i, number_of_cities;
struct City cities[10];
FILE* fp = fopen("cities.txt", "w");
fputs("Sarajevo 345123", fp); fputc(10, fp);
fputs("Tuzla 123456", fp); fputc(10, fp);
fputs("Mostar 101010", fp); fputc(10, fp);
fputs("Banja Luka 234987", fp);
fclose(fp);
number_of_cities = load(cities, 10);
printf("%d\n", number_of_cities);
for (i = 0; i < number_of_cities; i++)
printf("%s,%d\n", cities[i].name, cities[i].number_of_citizen);
return 0;
}
Could you explain me how to fix this? Why my program only loaded 1 city?
The fscanf() conversion string is incorrect: instead of "%[^,]s %d\n" you should use:
while (i < n && fscanf(fp, "%30[^,],%d",
cities[i].name,
&cities[i].number_of_citizen) == 2) {
i++;
}
Or better:
#include <errno.h>
#include <stdio.h>
#include <string.h>
int load(struct City cities[], int n) {
char buf[200];
int i = 0;
char ch[2];
FILE *fp = fopen("cities.txt", "r");
if (fp == NULL) {
fprintf(stderr, "cannot open %s: %s\n", "cities.txt",
strerror(errno));
return -1;
}
while (i < n && fgets(buf, sizeof buf, fp)) {
if (sscanf(buf, "%30[^,],%d%1[\n]",
cities[i].name,
&cities[i].number_of_citizen, ch) == 3) {
i++;
} else {
fprintf(stderr, "invalid record: %s\n", buf);
}
}
fclose(fp);
return i;
}
Also change your main function to output commas between the city names and population counts:
int main() {
int i, number_of_cities;
struct City cities[10];
FILE *fp = fopen("cities.txt", "w");
if (fp) {
fputs("Sarajevo,345123\n", fp);
fputs("Tuzla,123456\n", fp);
fputs("Mostar,101010\n", fp);
fputs("Banja Luka,234987\n", fp);
fclose(fp);
}
number_of_cities = load(cities, 10);
printf("%d\n", number_of_cities);
for (i = 0; i < number_of_cities; i++)
printf("%s,%d\n", cities[i].name, cities[i].number_of_citizen);
return 0;
}
EDIT: since there are no commas in the database file, you must use a different parsing approach:
#include <errno.h>
#include <stdio.h>
#include <string.h>
int load(struct City cities[], int n) {
char buf[200];
int i = 0;
FILE *fp = fopen("cities.txt", "r");
if (fp == NULL) {
fprintf(stderr, "cannot open %s: %s\n", "cities.txt",
strerror(errno));
return -1;
}
while (i < n && fgets(buf, sizeof buf, fp)) {
/* locate the last space */
char *p = strrchr(buf, ' ');
if (p != NULL) {
/* convert it to a comma */
*p = ',';
/* convert the modified line */
if (sscanf(buf, "%30[^,],%d",
cities[i].name,
&cities[i].number_of_citizen) == 2) {
i++;
continue;
}
}
fprintf(stderr, "invalid record: %s", buf);
}
fclose(fp);
return i;
}
So I have this code which I was working on. The goal is to search for a string in a file and when that string is found it would return the corresponding values in that section of the file. So this is the file in question that is being searched:
So if it finds "AJ" then it would return all the values right up to "22550" and if it finds "TS" then it prints everything after "TS" and after "60500." This is my code in question:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *name;
char *code;
int grpsize;
char route;
char *package;
//float fee;
float tcost;
float fcost;
} bookingrecord;
int main() {
FILE *fptr;
bookingrecord bookingrec;
char book_code[5];
printf("\n Please enter the code that corressponds to your record: ");
scanf("%s", book_code);
fptr = fopen("bookingdata", "r");
if (fptr == NULL) {
printf ("\nSorry we didn't find your file.");
exit (1);
}
ssize_t read;
char * line = NULL;
size_t len = 0;
int count = 0;
int found = 0;
while ((read = getline(&line, &len, fptr)) != -1) {
if (count == 0) {
bookingrec.code = line;
//printf("%s %s",bookingrec.code,book_code);
if (strcmp(bookingrec.code, book_code) == 0) {
found = 1;
}
} else if (count == 1 && found == 1) {
bookingrec.grpsize = line;
} else if (count == 2 && found == 1) {
bookingrec.route = line;
} else if (count == 3 && found == 1) {
bookingrec.fcost = strtof(line, NULL);
} else if (count == 4 && found == 1) {
bookingrec.name = line;
} else if (count == 5 && found == 1) {
bookingrec.package = line;
} else if (count == 6 && found == 1) {
bookingrec.tcost = strtof(line, NULL);
}
count = count + 1;
if(strlen(line) == 0) {
count = 0;
}
}
if (found == 1) {
printf("\n We have found your file");
printf("\n %s", bookingrec.code);
printf("\n %s", bookingrec.name);
printf("\n %d", bookingrec.grpsize);
printf("\n %s", bookingrec.route);
printf("\n %c", bookingrec.package);
printf("\n %.2f", bookingrec.tcost);
printf("\n %.2f", bookingrec.fcost);
}
fclose(fptr);
return 0;
}
The problem is that it only gives me this as the result:
So it finds the file okay but nothing happens so I uncomment a printf which I added to troubleshoot a bit right above my strcmp and get this when I enter for eg. "AJ":
I try another of the two character string. "SH" in this case and get this:
So it seems as if it is accepting any of the codes but prints the first line twice? But also discards everything else. I am a bit stumped as to what is happening. Any ideas?
Update:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *name;
char *code;
int grpsize;
char *route;
char *package;
//float fee;
float tcost;
float fcost;
} bookingrecord;
int main() {
FILE *fptr;
bookingrecord bookingrec;
char book_code[5];
printf("\n Please enter the code that corressponds to your record: ");
scanf("%s", book_code);
fptr = fopen("bookingdata", "r");
if (fptr == NULL) {
printf ("\nSorry we didn't find your file.");
exit (1);
}
ssize_t read;
char * line = NULL;
size_t len = 0;
int count = 0;
int found = 0;
while ((read = getline(&line, &len, fptr)) != -1) {
line[strcspn(line, "\r\n")] = 0; //trims getLine
//printf("line is %s, count is %d \n", line, count);//debugging
if (count == 0) {
bookingrec.code = strdup(line);
if (strcmp(bookingrec.code, book_code) == 0) {
found = 1;
}
} else if (count == 1 && found == 1) {
char *tmp;
bookingrec.grpsize = strtol(strdup(line), NULL, 10);
} else if (count == 2 && found == 1) {
bookingrec.route = strdup(line);
} else if (count == 3 && found == 1) {
bookingrec.fcost = strtof(strdup(line), NULL);
} else if (count == 4 && found == 1) {
bookingrec.name = strdup(line);
} else if (count == 5 && found == 1) {
bookingrec.package = strdup(line);
} else if (count == 6 && found == 1) {
bookingrec.tcost = strtof(strdup(line), NULL);
}
count = count + 1;
if (found == 1 && count == 7){
break;
}
if(strlen(line) == 0) {
count = 0;
}
}
if (found == 1) {
printf("\n We have found your file");
printf("\n %s", bookingrec.code);
printf("\n %s", bookingrec.name);
printf("\n %d", bookingrec.grpsize);
printf("\n %s", bookingrec.route);
printf("\n %s", bookingrec.package);
printf("\n %.2f", bookingrec.tcost);
printf("\n %.2f", bookingrec.fcost);
}
fclose(fptr);
return 0;
}
Updated screens after edits:
I have written a C program that opens a text file and compares the given string with the string present in the file. I'm trying to print the line number in which the same string occurs, but I am unable to get the proper output: output does not print the correct line number.
I would appreciate any help anyone can offer, Thank you!
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main() {
int num = 0, line_number = 1;
char string[50];
char student[100] = { 0 }, chr;
while (student[0] != '0') {
FILE *in_file = fopen("student.txt", "r");
if (in_file == NULL) {
printf("Error file missing\n");
exit(1);
}
printf("please enter a word \n");
scanf("%s", student);
while (fscanf(in_file, "%s", string) == 1) {
if (chr == '\n') {
if (strstr(string, student) == 0) {
break;
} else
line_number += 1;
}
}
printf("line number is: %d\n", line_number);
fclose(in_file);
}
return 0;
}
You cannot read lines with while (fscanf(in_file, "%s", string), the newlines will be consumed by fscanf() preventing you from counting them.
Here is an alternative using fgets():
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char string[200];
char student[100];
int num = 0, line_number = 1;
FILE *in_file = fopen("student.txt", "r");
if (in_file == NULL) {
printf("Error file missing\n");
exit(1);
}
printf("please enter a word \n");
if (scanf("%s", student) != 1) {
printf("No input\n");
exit(1);
}
while (fgets(string, sizeof string, in_file)) {
if (strstr(string, student)) {
printf("line number is: %d\n", line_number);
}
if (strchr(string, '\n')) {
line_number += 1;
}
fclose(in_file);
}
return 0;
}
I have some functions like push, pop, delete etc. for a singly linked list and implemented the following function to get user input:
void user_input(){
char input[10];
while(fgets(input, 9, stdin)){
if(strncmp(input, "add", 3) == 0){
int x;
printf("Number to add: ");
scanf("%d", &x);
push(x);
printf("%d added.\n", x);
}
else if(strncmp(input, "del", 3) == 0){
int x;
printf("Number to delete: ");
scanf("%d", &x);
delete(x);
printf("%d deleted.\n", x);
}
else if(strncmp(input, "q", 1) == 0){
printf("Program terminated.\n");
break;
}
// and some other if else statements...
}
So I can input a string like "add", then strncmp will compare it and I get another prompt asking me to enter the number I want to add and stores in x using scanf. Something like this:
add
Number to add: 5
5 added.
However I am looking for a way to be able to enter something like this:
add 5
del 2
etc.
Basically a string and int value in one line separated by space, instead of writing "add" first, pressing enter and writing the number. I tried using sscanf but had no luck yet.
It is much easier to step past input errors if you use fgets and then sscanf. You simply read another input string instead of messing around unblocking the input when invalid data was entered.
#include <stdio.h>
#include <string.h>
void push(int x) {
}
void delete(int x) {
}
void triple(int x, int y, int z) {
}
int main(void)
{
char input[100];
char oper[20];
int x, y, z; // romantic expansion for more than one argument
int res;
int err;
while(1) {
err = 0;
if(fgets(input, sizeof input, stdin) != NULL) {
res = sscanf(input, "%19s%d%d%d", oper, &x, &y, &z);
if(res == 2 && strcmp(oper, "add") == 0){
push(x);
printf("%d added.\n", x);
}
else if(res == 2 && strcmp(oper, "del") == 0) {
delete(x);
printf("%d deleted.\n", x);
}
else if(res == 4 && strcmp(oper, "trip") == 0) { // fantasy
triple(x, y, z);
printf("%d %d %d tripled.\n", x, y, z);
}
else if(res == 1 && strcmp(oper, "q") == 0){
printf("Program terminated.\n");
break;
}
// some other if else statements...
else {
err = 1;
}
}
else {
err = 1;
}
if(err) {
printf("Bad operation.\n");
}
}
return 0;
}
You could use scanf() like
char str[10];
int c;
if( scanf("%9s %d", str, &c)!=2 )
{
perror("Something went wrong.");
}
The width for %s is one less than the size of str. The extra character is for the \0.
scanf() returns the number of successful assignments that it made which in this case should be 2.
Now if you enter an input like
del 2
str will have "del" and c will have 2.
A good strategy for what are trying to do would be:
Read the input line by line.
Process each line.
Continue until there is no input or the user chose to quit.
Here's the core outline.
// Make LINE_SIZE big enough for your needs
#define LINE_SIZE 100
void processLine(char line[]);
int main()
{
char line[LINE_SIZE];
while ( fgets(line, LINE_SIZE, stdin) != NULL )
{
processLine(line);
}
}
void processLine(char line[])
{
}
In processLine, your first job is to pull the command. Do the needful based on the command.
void processLine(char line[])
{
char command[20];
int num = 0;
// Read the command and gather the number of characters read
// This allows you to read more data from (line + num)
int n = sscanf(line, "%19s%n", command, &num);
if ( n != 2 )
{
// Problem
exit(0);
}
// The command is to quit, exit.
if ( isQuitCommand(command) )
{
exit(0);
}
char* commandData = line + num;
if ( isAddCommand(command) )
{
processAdd(commandData);
}
else if ( isDeleteCommand(command) )
{
processDelete(commandData);
}
else { ... }
}
Here's a version of the program with stubs used for couple of functions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Make LINE_SIZE big enough for your needs
#define LINE_SIZE 100
void processLine(char line[]);
int isQuitCommand(char command[]);
int isAddCommand(char command[]);
int isDeleteCommand(char command[]);
void processAdd(char commandData[]);
void processDelete(char commandData[]);
int main()
{
char line[LINE_SIZE];
while ( fgets(line, LINE_SIZE, stdin) != NULL )
{
processLine(line);
}
}
void processLine(char line[])
{
char command[20];
int num = 0;
// Read the command and gather the number of characters read
// This allows you to read more data from (line + num)
int n = sscanf(line, "%19s%n", command, &num);
if ( n != 2 )
{
// Problem
exit(0);
}
// The command is to quit, exit.
if ( isQuitCommand(command) )
{
exit(0);
}
char* commandData = line + num;
if ( isAddCommand(command) )
{
processAdd(commandData);
}
else if ( isDeleteCommand(command) )
{
processDelete(commandData);
}
else
{
// ...
}
}
int isQuitCommand(char command[])
{
return (command[0] == 'q');
}
int isAddCommand(char command[])
{
return (strcmp(command, "add") == 0);
}
int isDeleteCommand(char command[])
{
return (strcmp(command, "del") == 0);
}
void processAdd(char commandData[])
{
// Add code to process commandData
}
void processDelete(char commandData[])
{
// Add code to process commandData
}