Getting an infinite running program when using scanf - c

I'm getting an infinite running programm when I use the following code to read a string from keyboard and save it within a structured vector.
scanf("%s", strk_zgr_fp->bezeichnung, (int)sizeof(strk_zgr_fp->bezeichnung - 1));
Simply nothing happens after this line is reached and the program runs infinitly.
I know scanf() isn't recommended. We're using it only within our C beginners course and I want you to keep it in mind, ie please don't recommend other function rather than above mentioned for the moment.
Any help is much appreciated, thanks in advance.
#include <stdio.h>
typedef struct {
int nummer;
char bezeichnung;
int menge;
float preis;
} artikel;
void eingabe_artikel(artikel *strk_zgr_fp, int i_fp);
void ausgabe_artikel(artikel *strk_zgr_fp, int i_fp);
void main(void) {
artikel artikelliste[10];
artikel *strk_zgr;
int anzahl;
do {
printf("Bitte eine #Artikel eingeben [<= 10]: ");
scanf("%d", &anzahl);
if(anzahl < 1 || 10 < anzahl)
printf("\nEs wurde eine falsche #Artikel eingegeben.");
} while(anzahl < 1 || 10 < anzahl);
for(int i = 0; i < anzahl; i++)
eingabe_artikel(&artikelliste[i], i);
int i;
for(strk_zgr = artikelliste, i = 0; strk_zgr < artikelliste + anzahl;
strk_zgr++, i++)
ausgabe_artikel(strk_zgr, i);
}
void eingabe_artikel(artikel *strk_zgr_fp, int i_fp) {
printf("\nBitte den %d. Artikel eingeben: ", ++i_fp);
printf("\nNummer: ");
scanf("%d", &strk_zgr_fp->nummer);
printf("Bezeichnung: );
scanf("%s", strk_zgr_fp, (int)sizeof(strk_zgr_fp->bezeichnung - 1)); /* <-- */
printf("Menge: ");
scanf("%d", &strk_zgr_fp->menge);
float preis;
printf("Preis: );
scanf("%f", &preis);
strk_zgr_fp->preis = preis;
}
void ausgabe_artikel(artikel *strk_zgr_fp, int i_fp) {
printf("\n%d. Artikel: ", ++i_fp);
printf("\nNummer:\t%d", strk_zgr_fp->nummer);
printf("\nBezeichnung:\t%s", strk_zgr_fp->bezeichnung);
printf("\nMenge:\t%d", strk_zgr_fp->menge);
printf("\nPreis:\t%.2f EUR\n", strk_zgr_fp->preis);
}
NetBeans Version
Complier Version

Many problems in the code. Please at least fix the missing ending quotes on the printf() calls.
Now to the beef:
1) Your structure is wrong. 'Bezeichnung' is defined as a single character, not a string.
typedef struct {
int nummer;
char bezeichnung[100];
int menge;
float preis;
} artikel;
2) You cannot use scanf() in the way you did. If you want to limit the input length (which always is a good idea), you need to pass the maximum length into the format string.
Do you nee to use scanf()?? Because it gets messy from here on....
As your maximum input length might be variable or subject to change (see 1.), you need to build the format string for scanf. Something like this:
char format_str[15];
format_str[0] = '%';
//Dont use itoa(), it is not C standard.
sprintf(&format_str[1], "%d", (int)sizeof(strk_zgr_fp->bezeichnung) - 1);
strcat(format_str, "s");
scanf(format_str, strk_zgr_fp->bezeichnung);
Hope that gets you going.
PS: You need to include string.h for strcat().

I tried it out and it worked fine for me. Not sure on this sprintf() function. Could you please explain why I'm supposed to use it? By now, I used this code: char format_str[20]; format_str[0] = '%'; strcat(format_str, "s"); printf("Bezeichnung: "); scanf(format_str, strk_zgr_fp->bezeichnung);
While that works, you are missing out on limiting the length of the user's input. That is why I proposed using sprintf() to create a (sub)string containing the maximal allowable length of the user input, depending on how large your 'bezeichnung' is defined in the struct. Suppose 'bezeichnung' has a limit of 100 characters, you would want to limit the input to 99 (+1 for the zero-termination), so you want a scanf format string like this: "%99s".
chux has provided a much more compact version of my three lines, but I think, in the beginning, you will have it easier to just assemble such format strings piece by piece, at the same time learning how to a) change individual characters in a string, how to use sprintf() in a basic way, and how to concatenate strings with strcat().
There was another example which I did and the course leader provided a scanf() function like this to read a string: scanf("%s", &(strk_zgr_fp->bezeichnung));. I thought when I'm reading a string the address operator isn't used. The only difference is the address operator now is used and the element was put into brackets.
Now, I think this is bad practice. It works, but is superfluous. Consider this small code snippet:
#include <stdio.h>
#include <stdlib.h>
struct test{
int i;
char a_str[10];
};
int main()
{
struct test a_test;
printf("Normal array adress taking: %p\n", a_test.a_str);
printf("Using '&' to take adress of array: %p\n", &(a_test.a_str));
return 0;
}
Hope that helps.

Related

How to separate character and number from string in c program

For example, I want to separate the string "0013subdivision" into 0013 (as an integer that can do addition, subtraction, etc. not char) and subdivision (as a char itself) in the given string.
This is my code so far:
#include <stdio.h>
#include <stdlib.h>
char location[10]; /* for the input with number and letter */
char x;
int house[10]; /* for the integer that will be separated from the string */
int main()
{
printf("Input: ");
scanf ("%s", &location[x]);
x=0
for (x=0; location[x]!='\0'; x++ );
return 0;
}
Based on my research, the code atoi is used to convert the converted value back to int (if I'm not mistaken) but I don't know when to place the function.
location is char array, if you are reading as string use only %s with string name only, index not required.
scanf ("%s", &location[x]); --> scanf ("%s", location);
After separating only int from char array you need to store one int value into house.
int house[10] --> int house.
Here is the code for extracting only int from string :
char location[10]; /* for the input with number and letter */
int x;
int house = 0 ; /* for the integer that will be separated from the string */
int main()
{
printf("Input: ");
//scanf ("%s", &location[x]);
scanf ("%s", location);
for (x=0; location[x]!='\0'; x++ ) {
if(location[x]>='0' && location[x]<='9') {
house =(house * 10) + (location[x]-48);
}
}
printf("int part = %d \n",house);
return 0;
}
The main problem in the code is
scanf ("%s", &location[x]);
Where you did not impose any limit on the scanning. An input like 0013subdivision will cause out of bound memory access leading to undefined behavior.
Always limit the input size with the length modifier, like, for an array defined as
char location[10]
use the conversion specification like
scanf ("%9s", location); // (i) one element saved for terminating null
// (ii) the array name decays to the pointer to 1st element
//in case of an argument to a function call.
Then, you don't need an integer array to store the extracted integer. A singular variable would suffice.
However, i'd like to suggest a much robust way:
read the user input using fgets()
then, scan the input using sscanf() and appropriate conversion specifier, like %4d%9s or alike.
The most correct way to do this is to use the strto... family of functions from stdlib.h. For example:
printf("%ld\n", strtol(str, NULL, 10));
The atoi family of functions should never be used for any purpose, since they have broken error handling and can be 100% replaced by the strto... functions.
You could use the scanf family of functions but they are needlessly slow and notoriously dangerous, so I don't really see the point of using them here.
If you are interested in implementing the actual copying manually, for learning purposes, it is fairly trivial:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main (void)
{
const char str[] = "0013subdivision";
char number_part [sizeof(str)];
char letter_part [sizeof(str)];
size_t i;
for(i=0; str[i]!='\0' && isdigit(str[i]); i++) // find where the letters start
{}
memcpy(number_part, &str[0], i); // copy digit part
number_part[i] = '\0'; // append null terminator
memcpy(letter_part, &str[i], sizeof(str)-i); // copy letter part + null term
puts(number_part);
puts(letter_part);
printf("%ld\n", strtol(str, NULL, 10));
}
If the string is a run-time variable, you have to use strlen(str)+1 instead of sizeof().
strtol converts string to number and also gives you back the character it stopped on, i.e. first character after number.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
const char* const input = "0013subdivision";
const char* string;
const long number = strtol(input, &string, 10);
printf("Number: %ld String: '%s'\n", number, string);
// Number: 13 String: 'subdivision'
return 0;
}
https://repl.it/repls/SphericalImpracticalTinamou

C programming, error loop due to scanf?

I have question about scanf a string. I am completing a practice exercise on encoding a Vigenere cipher.
It is easy to solve it at other language but in C I have trouble and I don't know why it is.
This is my code.
#include<stdio.h>
#include<string.h>
main()
{
char mes[1000];
char key[100];
int n=strlen(mes);
int cipher[n],i,j=0;
printf("Enter message \n");
scanf("%s",mes);
printf("Enter keyword \n");
scanf("%s",key);
printf("len message= %d \n",strlen(mes));
for(i=0;i<strlen(mes);++i)
{
mes[i]=toupper(mes[i]);
key[j]=toupper(key[j]);
if(j==strlen(key))
j=0;
cipher[i]=((mes[i]-0x41)+(key[j]-0x41)) % 26;
printf("%c",cipher[i]+0x41);
++j;}
printf("\n");
}
My code work well if mes array input is less than 16 character, but if mes input larger the program loop infinite. I don't know why.
If I change type of cipher array to char type, it seem work better, but the result still have wrong output like this:
Enter message
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Enter keyword
eeeeeeeeeeeeeeeeeee
len of message= 45
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE�EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEAEEEEEEE
So can you explain:
1) Why my code do wrong if cipher array is an int type?
2) If cipher is char, the output better but why It have wrong output?
Couple of problems:
Allocating memory for cipher doesn't work properly
int n=strlen(mes); // mes has nothing now..so n=0!
int cipher[n],i,j=0;
Rolling back j should be done after increment .
Put this piece after you read both inputs..it should work for any length<100
int cipher[strlen(mes)];
for(i=0;i<strlen(mes);++i)
{
mes[i]=toupper(mes[i]);
key[j]=toupper(key[j]);
cipher[i]=((mes[i]-'A')+(key[j]-'A')) % 26; //use 'A' for better readability
printf("%c",cipher[i]+'A');
++j;
if(j==strlen(key))
j=0;
}
In simple words, You wrote int n=strlen(mes); before giving any input,Now how would you determine the size of input when its still not given,See my comments in below code,
char mes[1000];
char key[100];
int n,i,j=0;
printf("Enter message \n");
scanf("%s",mes);
n=strlen(mes);//Determining Size of Input after giving it.....
int cipher[n];//Add This Here,Now You Create a array after Determining input size.
printf("Enter keyword \n");
scanf("%s",key);
printf("len message= %d \n",strlen(mes),strlen(key));
You didn't initiate the length of the chiper array correctly.. In your code:
char mes[1000];
char key[100];
int n=strlen(mes);
int cipher[n];
The length of chiper array here is undefined..
Unless you write something like:
int chiper[1000];
BR//Ari

reading multiple variable types from single line in file C

Alright I've been at this all day and can't for the life of me get this down, maybe you chaps can help. I have a file that reads as follows
1301,105515018,"Boatswain","Michael R.",ABC, 123,="R01"
1301,103993269,"Castille","Michael Jr",ABC, 123,="R03"
1301,103993267,"Castille","Janice",ABC, 123,="R03"
1301,104727546,"Bonczek","Claude",ABC, 123,="R01"
1301,104731479,"Cruz","Akeem Mike",ABC, 123,="R01"
1301,105415888,"Digiacomo","Stephen",ABC, 123,="R02"
1301,106034479,"Annitto Grassis","Susan",ABC, 123,="R04"
1301,106034459,"Als","Christian",ABC, 123,="R01"
And here is my code...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_NAME 15
#define MAX_SUBSEC 3
#define N 128
//void printArr(struct *students);
struct student{
int term;
int id;
char lastname[MAX_NAME];
char firstname[MAX_NAME];
char subjectname[MAX_SUBSEC];
int catalog;
char section[MAX_SUBSEC];
}students[10];
int main(){
int term;
int id;
char lastname[MAX_NAME];
char firstname[MAX_NAME];
char sub[MAX_SUBSEC];
int cat;
char sec[MAX_SUBSEC];
char fname[N];
FILE *inputf;
printf("Enter the name of the text file: ");
scanf("%123s",fname);
strcat(fname,".txt");
inputf = fopen(fname,"r");
if (inputf == NULL){
printf("I couldn't open the file for reading.\n");
exit(0);
}
//TROUBLE HERE!
fscanf(inputf, "%d,%d,%[^,]s", &students[0].term, &students[0].id,students[0].lastname);
printf("%d\n", students[0].term);
printf("%d\n", students[0].id);
printf("%s\n", students[0].lastname);
/*for (j = 1 ; j <= 10-1 ; j++){
for(k = 0 ; k <= 10-2 ; k++){
if(students[k] > students[k+1]){
temp = students[k];
students[k] = students[k+1];
students[k+1] = temp;
}
}
}*/
fclose(inputf);
system("pause");
return 0;
}
void printArr(int a[], int tally){
int i;
for(i = 0 ; i < tally ; i++){
printf("%d ", a[i]);
}
printf("\n");
}
My objective is to take each one of those values in the text file and input it to where it belongs in the struct and subsequently the struct array, but I can't get passed the first 2 ints.
Getting the lastname string, because it is a max of 15 characters, it spills over into the first name string right after it and takes what remaining characters it needs in order to fill up the lastname char array. Obviously I do not want this. As you can see I have tried strtok but it doesnt do anything, not sure what I have to do though as I have never used it before. Also have tried just including all the variables into fscanf statement, but I either get the same output, or it becomes a mess. As it is, I am extremely lost, how do I get these values into the variables they belong?!
EDIT: updated my code, I have gotten a little farther but not much. I can now print out just the last name but can not more farther from there, I cant get to the firstname string or any of the variables beyond it.
What you have there is a CSV file with quoted strings, and so I would recommend you use a CSV parser (or roll your own) rather than trying to do it all with scanf (since scanf cannot deal with quotes, e.g. commas within quoted strings). A quick Google search turns up libcsv.c which you may be able to use in your project.
With the fscanf format string "%d,%d,\"%[^\"]\",\"%[^\"]\",%[^,],%d,=\"%[^\"]\"" we can read a whole line's data. Besides, you have to define
char lastname[MAX_NAME+1];
char firstname[MAX_NAME+1];
char subjectname[MAX_SUBSEC+1];
int catalog;
char section[MAX_SUBSEC+1];
— the +1 to account for the terminating '\0' character.
I have a question for you... If you want to know how to use a diamond cutter, do you try it and see, or do you consult the manual? The problem here isn't the result of your choice, but your choice itself. Believe it or not, I have answered these questions so often that I'm tired of repeating myself. The answer is all in the manual.
Read the POSIX 2004 scanf manual — or the POSIX 2008/2013 version — and the answer this question and you'll have some idea of what you're not doing that you should be. Even fscanf code should use assert as a debugging aid to ensure the number of items read was correct.
%[^,]s It seems as though there's a mistake here. Perhaps you meant %[^,]. The %[ format specifier is a different format specifier to the %s format specifier, hence in the presumably mistaken code there are two directives: %[^,] and s. The s directive tells scanf to read an 's' and discard it.
1.There is a syntax error in
while(result != NULL){
printf(".....);
......
}
}//error
fscanf(inputf, "%s", lastname); can't read a line ,fscanf will stop when it comes across an space
fscanf reads one line at a time, and you can easily capture the contents of each line because your file is formatted pretty nicely, especially due to the comma separation (really useful if none of your separated values contain a comma).
You can pass fscanf a format like you're doing with "%d" to capture an int, "%s" to capture a string (ends at white space, be weary of this when for example trying to find a name like "Annitto Grassis, which would require 2 %s's), etc, from the currently read line of the file. You can be more advanced and use regex patterns to define the contents you want captured as chars, such as "Boatswain", a sequence comprised chars from the sets {A-Z}, {a-z}, and the {"}. You'll want to scan the file until you reach the end (signified by EOF in C) so you can do such and capture the contents of the line and appropriately assign the values to variables like so:
while( fscanf(inputf, "%d,%d,%[\"A-Za-z ],%[\"A-Za-z .]", &term, &id, lastname, firstname) != EOF) {
.... //do something with term, id, lastname, firstname - put them in a student struct
}
For more about regex, Mastering Regex by Jeff Friedl is a good book for learning about the topic.

Scanning, Checking, Converting, Copying values ... How to ? -- C --

Its been a while now and im still trying to get a certain code to work. I asked some question about different commands etc. before, but now I hope this is the final one (combining all questions in one code).
I basically want to :
*Scan an input (should be character ? )
*Check if its a number
*If not, return error
*Convert that character into a float number
*Copy the value to another variable ( I called it imp here)
Here is what I came up with :
EDITED CODE*
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
main(){
int digits;
float imp=0;
char* alpha;
do{
printf("Enter input\n\n");
scanf("\n%c",alpha);
digits=isdigit(alpha);
if(digits==0){
printf("error\n\n");
}
imp=atof(alpha);
}while(digits==0);
}
The problem is this code does not work at all ... It gives me that atof must be of a const char and whenever I try changing it around, it just keeps failing. I am frustrated and forced to ask here, because I believe I have tried alot and I keep failing, but I wont be relieved until I get it to work xD So I really need your help guys.
Please tell me why isnt this code working, what am I doing wrong ? I am still learning C and really appreciate your help :)
EDIT
Error given atm is :
Argument no 1 of 'isdigit' must be of type 'const int', not '<ptr>char'
EDIT
This code compiles fine, but crashes when an input is entered.
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
main(){
int digits;
float imp=0;
char* alpha=0;
do{
printf("Enter input\n\n");
scanf("\n%s",alpha);
digits=(isdigit(alpha[0]));
imp=atof(alpha);
}while(digits==0);
}
Why not have scanf do the atof conversion for you?
#include <stdio.h>
int main()
{
float imp=0;
while (1)
{
printf("Enter input\n\n");
if (scanf("%f", &imp) < 1) break;
}
return 0;
}
Your most recent example is failing because alpha is a NULL pointer. Declare it as char alpha[40]; to allocate space for it. You'll probably want to use %40s in your format string to prevent scanf from overflowing alpha.
Also, use strtod instead of atof and you'll know whether the conversion was successful (better than your method of using isdigit which will fail on a negative integer).
You probably need to use %s instead of %c and to put it in char array (char*). You also probably get an error that you need to use const char* and not const char.
You don't want to read just one character - you want to read an entire string...
EDIT:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
main(){
int digits,i;
float imp=0;
char* alpha = malloc(100); /* 100 is for example */
do{
printf("Enter input\n\n");
scanf("\n%s",&alpha);
for (i = 0; i != 100; ++i)
{
if (alpha[i] == '\0')
break;
if (!isdigit(alpha[i]))
{
printf("error\n\n");
return ...;
}
}
imp=atof(alpha);
}while(true);
}

How do you read from a file into an array of struct?

I'm currently working on an assignment and this have had me stuck for hours. Can someone please help me point out why this isn't working for me?
struct book
{
char title[25];
char author[50];
char subject[20];
int callNumber;
char publisher[250];
char publishDate[11];
char location[20];
char status[11];
char type[12];
int circulationPeriod;
int costOfBook;
};
void PrintBookList(struct book **bookList)
{
int i;
for(i = 0; i < sizeof(bookList); i++)
{
struct book newBook = *bookList[i];
printf("%s;%s;%s;%d;%s;%s;%s;%s;%s;%d;%d\n",newBook.title, newBook.author, newBook.subject,
newBook.callNumber,newBook.publisher, newBook.publishDate, newBook.location, newBook.status,
newBook.type,newBook.circulationPeriod, newBook.costOfBook);
}
}
void GetBookList(struct book** bookList)
{
FILE* file = fopen("book.txt", "r");
struct book newBook[1024];
int i = 0;
while(fscanf(file, "%s;%s;%s;%d;%s;%s;%s;%s;%s;%d;%d",
&newBook[i].title, &newBook[i].author, &newBook[i].subject,
&newBook[i].callNumber,&newBook[i].publisher, &newBook[i].publishDate,
&newBook[i].location, &newBook[i].status,
&newBook[i].type,&newBook[i].circulationPeriod, &newBook[i].costOfBook) != EOF)
{
bookList[i] = &newBook[i];
i++;
}
/*while(fscanf(file, "%s;%s;%s;%d;%s;%s;%s;%s;%s;%d;%d",
&bookList[i].title, &bookList[i].author, &bookList[i].subject,
&bookList[i].callNumber, &bookList[i].publisher, &bookList[i].publishDate,
&bookList[i].location, &bookList[i].status, &bookList[i].type,
&bookList[i].circulationPeriod, &bookList[i].costOfBook) != EOF)
{
i++;
}*/
PrintBookList(bookList);
fclose(file);
}
int main()
{
struct book *bookList[1024];
GetBookList(bookList);
}
I get no errors or warnings on compile
it should print the content of the file, just like it is in the file.
Like this:
OperatingSystems Internals and Design principles;William.S;IT;741012759;Upper Saddle River;2009;QA7676063;Available;circulation;3;11200
Communication skills handbook;Summers.J;Accounting;771239216;Milton;2010;BF637C451;Available;circulation;3;7900
Business marketing management:B2B;Hutt.D;Management;741912319;Mason;2010;HF5415131;Available;circulation;3;1053
Patient education rehabilitation;Dreeben.O;Education;745121511;Sudbury;2010;CF5671A98;Available;reference;0;6895
Tomorrow's technology and you;Beekman.G;Science;764102174;Upper Saddle River;2009;QA76B41;Out;reserved;1;7825
Property & security: selected essay;Cathy.S;Law;750131231;Rozelle;2010;D4A3C56;Available;reference;0;20075
Introducing communication theory;Richard.W;IT;714789013;McGraw-Hill;2010;Q360W47;Available;circulation;3;12150
Maths for computing and information technology;Giannasi.F;Mathematics;729890537;Longman;Scientific;1995;QA769M35G;Available;reference;0;13500
Labor economics;George.J;Economics;715784761;McGraw-Hill;2010;HD4901B67;Available;circulation;3;7585
Human physiology:from cells to systems;Sherwood.L;Physiology;707558936;Cengage Learning;2010;QP345S32;Out;circulation;3;11135
bobs;thomas;IT;701000000;UC;1006;QA7548;Available;Circulation;7;5050
but when I run it, it outputs this:
OperatingSystems;;;0;;;;;;0;0
Internals;;;0;;;;;;0;0
and;;;0;;;;;;0;0
Design;;;0;;;;;;0;0
principles;William.S;IT;741012759;Upper;41012759;Upper;;0;;;;;;0;0
Saddle;;;0;;;;;;0;0
River;2009;QA7676063;Available;circulation;3;11200;lable;circulation;3;11200;;0;;;;;;0;0
Communication;;;0;;;;;;0;0
Thanks in advance, you're a life saver
I think your problem is that your fields contain spaces. fscanf will stop scanning a string (%s) when it sees a white space character. You need to change your %s format specifiers to allow spaces to be included. You can either just exclude your delimiter, e.g. %[^;] or specify what characters to include, e.g. %[ a-zA-Z0-9-] (I think I'd probably go for the first option).
% man fscanf
Not the cause, but in your PrintBookList method, you have
for(i = 0; i < sizeof(bookList); i++)
but you can't get the size of an array of structs that way (it returns 4, the size of a pointer).
It is standard practice to pass the size in:
void PrintBookList(struct book **bookList, int numBooks)
Don't forget to limit size of read strings (don't forget they end with a '\0' symbol) (scanf doesn't know how long the fields are).
scanf("%24[^;],...

Resources