Error message: Conversion may lose significant digits - c

C Program to accept and display "5" characters using getchar() and putchar() functions:
#include<stdio.h>
void main()
{
char ch[6];
ch[0]=getchar();
ch[1]=getchar();
ch[2]=getchar();
ch[3]=getchar();
ch[4]=getchar();
putchar(ch[0]);
putchar(ch[1]);
putchar(ch[2]);
putchar(ch[3]);
putchar(ch[4]);
}
When i am Compiling this code in "C" language then it is displaying this Error message:
"Conversion may lose significant digits", what could be the reason?

getchar returns an int and you're storing it in a char.
You can fix this by changing char ch[6]; to int ch[6];.

getchar() returns an int, to allow for passing additional values which are not in the range of valid characters. This allows for failures and error codes to be returned as values without overloading a particular character with multiple meanings. In normal operation any valid character may be returned, in error operation an int that is too large to fit in a char is returned.
The warning message indicates that you are going to only look at the char portion of the returned value, and as such, you might oddly cast an error or special return value into a char that wasn't actually captured.
--- Edited at the request of gautham to demonstrate good error detection ---
The lack of error checking for input failure can be fixed in one of two ways. The firs one is more common, and works on all systems where the size of an integer is greater than the size of a character.
// an ok approach which works for most systems
// provided that sizeof(int) != sizeof(char)
int c = getchar();
if (EOF != c) {
ch[0] = (char)c;
} else {
// some error occurred during input capture
// which resulted in getchar returning EOF
}
The second solution to error checking for input failure doesn't rely on the size of an integer being larger than the size of a character. It will work on all systems.
// a better approach which works for all systems
// even where sizeof(int) == sizeof(char)
c = getchar();
if (!feof(stdin) && !ferror(stdin)) {
// even if c was EOF, we know it's a char value, not an error value
ch[0] = c;
} else {
// c's value is EOF because of an error capturing the input, and
// not because a char value equaling EOF was read.
}
putting it all together to rewrite your program
#include<stdio.h>
int main(int argc, char** argv)
{
char ch[6];
ch[0]=getchar();
ch[1]=getchar();
ch[2]=getchar();
ch[3]=getchar();
ch[4]=getchar();
putchar(ch[0]);
putchar(ch[1]);
putchar(ch[2]);
putchar(ch[3]);
putchar(ch[4]);
return 0;
}
or if you have been introduced to procedures, the much better version of the above
#include<stdio.h>
char getInput() {
int c = getchar();
if (!feof(stdin) && !ferror(stdin)) {
return (char)c;
} else {
exit(EXIT_FAILURE);
}
}
int main(int argc, char** argv)
{
char ch[6];
ch[0]=getInput();
ch[1]=getInput();
ch[2]=getInput();
ch[3]=getInput();
ch[4]=getInput();
putchar(ch[0]);
putchar(ch[1]);
putchar(ch[2]);
putchar(ch[3]);
putchar(ch[4]);
return 0;
}
and if you have learned a bit about looping, it can be rewritten with a loop like so
#include<stdio.h>
char getInput() {
int c = getchar();
if (!feof(stdin) && !ferror(stdin)) {
return (char)c;
} else {
exit(EXIT_FAILURE);
}
}
int main(int argc, char** argv)
{
char ch[6];
int index;
for (index = 0; index < 5; index++) {
ch[index] = getInput();
}
for (index = 0; index < 5; index++) {
putchar(ch[index]);
}
return 0;
}
There are other checks you might want to add, like checking to see if your putchar failed due to an error during output; but, if you don't have an alternative means of presenting the error (like writing it to a file) then adding such checks only increase the complexity of the code without providing a means of communicating the error to the end user.
Error checking is one of the most important items in writing robust programs, but in most programming courses it is treated very lightly (if it is covered at all). If you don't get much discussion about error checking, do yourself a favor and independently read over <errno.h>. A decent description of how to handle errors in C can be found in the GNU pages disussing error handling. A basic "print to stderr" error handler might look like
// this defines errno
#include <errno.h>
// this defines perror
#include <stdio.h>
// this defines strerror
#include <string.h>
extern volatile int errno;
void printError(int value) {
perror(strerror(value));
}

Related

UndefinedBehaviorSanitiser Issue - CS50 Vigenere

I am working on Vigenere (CS50) and keep getting an "UndefinedBehaviorSanitiser SEGV on Unknown Address" when I run my program with any argument that passes the initial screening.
I have read about this issue but cannot find the solution. I cut my code down as much as I could and found the problem occurs even when I do this part. Where is the issue?
Thank you so much.
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
//int shift(char c);
int main(int argc, string argv[])
{
if (argc != 2)
{
printf("Usage: ./vigenere keyword");
return 1;
}
else
{
for (int i = 0; i < strlen(argv[1]); i++)
{
if (!isalpha(argv[1]))
{
printf("Usage: ./vigenere keyword");
return 1;
}
else
{
printf("All good!");
return 1;
}
}
}
}
The fix indeed is
if (!isalpha((unsigned char)argv[1][i]))
The isalpha function/macro takes only a single integer, which must have the value of a single character as unsigned char. But argv[1] is a pointer to multiple characters!
Now as an extra complication, the isalpha is often realized as a macro, and often coded so that a compiler does not produce any diagnostics for a wrong type of argument. This is unfortunate, but you just need to know these when you're programming in C.
The cast of char to unsigned char is required too - if not, then any extended characters (i.e. for example รค) will invoke undefined behaviour on platforms where char is signed - and they are on x86 processors - because the value will be negative, but isalpha would expect just a number that is either EOF or a non-negative number less than or equal to UCHAR_MAX.

add break statement in while loop with getchar

i am a starter and i have written a code:
#include<stdio.h>
char c;
char a[100]={0};
int i;
int main(void)
{
while(1)
{
i=0;
while(1){
if((c=getchar())!='\n'){
a[i]=c;
i++;
} else {
break;
}
}
printf("%s\n",a);
}
return 0;
}
and now i have idea that i want to add a break statement that when i type q, the program will break. so my new program is:
#include<stdio.h>
char c;
char a[100]={0};
int i;
int main(void)
{
while(1)
{
i=0;
while(1){
if((c=getchar())!='\n'){
a[i]=c;
i++;
} else {
break;
}
}
printf("%s\n",a);
if(getchar()=='q')break; /*i added this*/
}
return 0;
}
i know because the getchar() conflict the code is not correct, how can i do, to add the type q break command. thanks a lot.
i am a starter and i have written a code
Uh oh! Here goes... Firstly, the odds of successfully learning the portable, standard-compliant C programming language are overwhelmingly low for anyone who tries to learn by unguided trial and error. There's a really nice book you can use as a guide, but you need to read it AND do the exercises as you stumble across them. That's K&R2E, if you're interested.
Anything resembling char c; c = getchar(); is erroneous because the narrowing conversion from int (which getchar returns) to char discards error handling information.
Any character values returned by getchar will be as unsigned char values converted to an int, so it'd technically be more correct (though still incorrect) to use that type.
Error values are returned as a negative integer such as EOF, not to be confused with character values, which is exactly what your code does wrong by discarding the error information.
getchar returns int, so store the value into an int, then test for errors, then, if you must, convert it down to an unsigned char.
and now i have idea that i want to add a break statement that when i type q, the program will break.
Following on from the previous discussion, such a requirement is superfluous, nonetheless easy to incorporate if you're handling errors correctly. Just insert an extra test to match against q into the error handling, and presto!
Nonetheless, the error handling most likely already solves this problem, as most OSes have a mechanism to close stdin, which would cause getchar to return EOF, thus triggering the error handling clause. This is typically achieved by pressing CTRL+d in Linux, or CTRL+z in Windows, for example.
In conclusion, providing you aren't already reading one, it seems a nice book about C isn't all that'd benefit you; a nice book about console scripting for your favourite Unix-like OS would also be highly beneficial.
Unlikely to be what you actually want, but at least this will work
#include<stdio.h>
int main(void)
{
char a[100]={0};
int i = 0;
do {
int c = getchar();
switch (c) {
case EOF:
/*EOF*/
return -1;
case '\n':
a[i] = 0;
printf("%s\n",a);
i= 0;
break;
default:
a[i++] =c;
break;
} while (c != 'q' || i > 1);
return 0;
}
Try this code:
#include <stdio.h>
#include <stdlib.h>
#define q 113 --> These values are coming from ASCII table.
#define Q 81
int main(void)
{
char ch = 0;
do
{
ch = getchar();
switch(ch)
{
case q:
// your logic goes here
exit(0);
case Q:
// your logic goes here
exit(0);
/* more cases can come here */
}
}
while(1);
}

Error in "if not true" - C

I'm kinda new in C so I don't know if im allowed do to the following "if" in C, my error happens in the if line but the error is a segmentation fault, that should be a uninitialized variable but i give her a value from a file...well, there is the code:
char t1, ch;
if((fscanf(f,"P%d", &t1)) == 1){
if(!((strcmp(t1,"P2")==0) || (strcmp(t1,"P5")==0))){ // error here
fprintf(stderr, "\nTipo de imagem invalido.\n");
fclose(f);
return NULL;
}
If anyone can help me i will appreciate...
Thank you in advance!
Edit: I have rewritten answer to be complete and correct.
You are expecting to put an integer %d into a of char, which are most likely of different sizes. int is at least same size, and often bigger, so probably this is 1st place that should have blown up.
You can look at table here to figure out what format string specifier to use to match size of the variable you are reading. For a char it should be %hhd.
Also please note you use a string comparison function strcmp for a single character. Not sure why compiler did not point out type miss-match between char* and char.
You could force it to work with &t1 but it could end up with memory access faults, as strcmp expects the input to be a null-terminated string, which for single character is valid only for an empty string '\0'.
Also. If you write a format string like "P%s" the P symbol will not appear in the output.
What you can do.
Sticking to the string is tricky.
You could read whole string, like P3, and compare strings as you do, however you need to remember that they are null terminated. So to hold P3 you need something like char t1[3]. char t1; will certainly not hold "P3".
Also, unless your input is well formed and you are sure of, it is dangerous to read string from scanf with plain %s. You never know how long the input will be and it might end up overflowing your buffer...
You should specify the length of the string to read e.g. %2s.
#include <stdio.h>
#include <stdlib.h>
#define TYPE_SIZE 2
char ch;
int size;
char t1[TYPE_SIZE+1];
int main(){
if( (scanf("%2s", &t1) == 1)){
printf("t1=%s", t1);
if(!((strcmp(t1,"P2")==0) || (strcmp(t1,"P5")==0))){ // error here
fprintf(stderr, "\nTipo de imagem invalido.\n");
return -1;
}
} else fprintf(stderr, "Wrong input.\n");
return 0;
}
Still with this if you will input P5456456, there will be no error. You would need to consume input after 1st two characters and test it. You also need to keep track of max type length. You could also change TYPE_SIZE to something extra large in advance, but it is something to look for, and buggy prone (more theoretical, but still). Whenever you change TYPE_SIZE you need to update the format string, or construct it dynamically - more code.
Personally I would probably try reading type number into an integer and construct the if vs it.
#include <stdio.h>
#include <stdlib.h>
char ch;
int size;
unsigned char t1;
int main(){
if( (scanf("P%hhu", &t1) == 1)){
printf("t1=%u\n", t1);
if(!((t1 == 2) || (t1 == 5))){ // error here
fprintf(stderr, "\nTipo de imagem invalido.\n");
return -1;
}
} else fprintf(stderr, "Wrong input.\n");
return 0;
}
You should get segmentation fault even in
if((fscanf(f,"P%d", &t1)) == 1){
You should use
int t1;
In strcmp, you are passing t1 which is char not const char *. Here, char value is being typecasted to a pointer and now it tries to access the value at the location of t1. And this results in segmentation fault. So change is
int t1;
if((fscanf(f,"P%d", t1))){
if(!((2 == t1) || (5 == t1))){ // error here
fprintf(stderr, "\nTipo de imagem invalido.\n");
fclose(f);
return NULL;
}

C echo user input

So I am a very beginner to C programming (I have used Ruby, Python and Haskell before) and I am having trouble getting the most simple thing to work in C (probably because of all the manual memory stuff). Anyway, what I am trying to do is (using simple constructs) make a script that just echoes what the user inputs to the console.
e.g. user inputs hi, console prints hi.
This is what I came up with.
Also, I haven't really mastered pointers, so none of that.
// echo C script
int echo();
int main() {
echo();
return 0;
}
int echo() {
char input[500];
while (1) {
if (scanf("%[^\n]", input) > 0) {
printf("%s\n", input);
}
input[0] = 0;
}
return 1;
}
I realize that there is a bunch of bad practices here, like setting a giant string array, but that is just for simplifying it.
Anyway, my problem is that it repeats the first input then the input freezes. As far as I can tell, it freezes during the while loop (1 is never returned).
Any help would be appreciated.
Oh, and using TCC as the compiler.
You don't need an array for echo
#include <stdio.h>
int main(void)
{
int c;
while((c = getchar()) != EOF) putchar(c);
return 0;
}
It's fine that you have such a large string allocated, as long as it's possible for users to input a string of that length. What I would use for input is fgets (read this for more information). Proper usage in your situation, given that you still would like to use the string of size 500, would be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int echo(){
char input[500];
while(fgets(input, 500, STDIN)){ //read from STDIN (aka command-line)
printf("%s\n", input); //print out what user typed in
memset(input, 0, strlen(input)); //reset string to all 0's
}
return 1;
}
Note that changing the value of 500 to whatever smaller number (I would normally go with some power of 2 by convention, like 512, but it doesn't really matter) will limit the length of the user's input to that number. Also note that I didn't test my code but it should work.
scanf("%[^\n]", input
Should be:
scanf("%s",input)
Then after your if you should do:
memset(input,0,500);
There are many ways of accomplishing this task however the easiest would be to read from stdin one byte at a time and output that byte to stdout as you process each byte.
Snippet:
#include <stdio.h>
int main( void ) {
// Iterates until EOF is sent.
for ( int byte = getchar(); byte != EOF; byte = getchar() ) {
// Outputs to stdout the byte.
putchar( byte );
}
return 0;
}
Remark:
You must store the byte that you are reading through stdin in an integer. This is because you are not guaranteed that char is signed or unsigned, there are in fact 3 char types in C (char, signed char and unsigned char). Include the limits library to determine whether a char is signed or not in your environment.
You must compile using the C99 standards, otherwise move the declaration of byte outside of the for loop.

Passing file pointer into functions, and file not being read correctly

I think my problem with my code that the file is not being passed correctly. The input is a file with three lines
1 2 3;
4 5 6;
7 8 9;
and the output is a Segmentation fault (core dumped), the output is supposed to print the first line 1 2 3.
#include <stdio.h>
#include <stdlib.h>
int getNum();
int getLine();
int getMatrix();
int det1();
int det2();
int det3();
int det4();
int det5();
int det6();
main(){
FILE *infile;
infile = fopen("matrix.txt","r");
int line[6];
int lineSize;
int error;
getLine(line,lineSize,infile);
printf("%d %d\n", line[0],line[1]);
fclose(infile);
}
/***********************************************
Name : getLine
Description : To get the line of numbers
Arguments : infile - the file pointer with numbers inside
line[] - the line of numbers
lineSize - size of line
Returns : 1 - If no errors were encountered
2 - If END OF FILE was reached
-1 if non number detected
*************************************************/
int getLine(int line[], int lineSize, FILE *infile){
int value;
int l;
lineSize=0;
while(value != '\n'){
value=0;
l=getNum(value,*infile);
if (value==EOF){
return(2);
}
line[lineSize]=value;
lineSize++;
}
if (l == -1){
return(-1);
}
return(1);
}
/***********************************************
Name : getNum
Description : To get the Next number from file
Arguments : infile - the file with numbers inside
value - the value of number grabed
Returns : 1 - If no errors were encountered
-1 - If letter or non number detected
*************************************************/
int getNum(int value, FILE *infile){
int c;
int error=1;
while ((c=getc(infile)) != EOF){
if (c=='\n'){
value = '\n';
return(1);
}
if(c==32){//checking for space
if (error == -1){
return(-1);
}
else{
return(1);
}
}
else {
value = 10*value + c - '0';
}
if((c<=47)||(c>=58)){
printf("incorrect number input %d\n",c);
error = -1;
}
}
value = EOF;
return(1);
}
Skimming your code ...
int getNum();
int getLine();
int getMatrix();
int det1();
/* ... */
These declarations say to the compiler: "hey compiler, please be aware I'll be calling functions with these names (getNum, getLine, getMatrix, det1, ...) and they return int, but I'm not telling you what parameters they accept. Just trust me when I use them"
It's better if you use the prototype right when you introduce the functions to the compiler
int getNum(int value, FILE *infile);
int getLine(int line[], int lineSize, FILE *infile);
/* ... */
These declarations say to the compiler: "hey compiler, please be aware I'll ba calling function with these names, they return int and accept these parameters. If I make a mistake, do complain to let me know of my mistake"
... continuing inside main()
/* ... */
int lineSize;
int error;
getLine(line,lineSize,infile);
/* ... */
you declared lineSize but didn't provide a value for the variable. When the program calls getLine, the value for lineSize is almost certainly the wrong value (it might even make your computer crash even before calling the function). Initialize (almost) all variables before using them.
/* ... */
int lineSize = 0;
int error = 0;
getLine(line,lineSize,infile);
/* ... */
I haven't skimmed more ...
Suggestion: crank up your compiler warning level and do not run your program while compilation produces warnings.
In getLine(), when you give the infile FILE* to the getNum() function, you dereference it:
l=getNum(value,*infile);
But getNum() would just expect a normal FILE*, not a dereferenced one. So pass infile to that function unchanged:
l=getNum(value,infile);
Additionally, the while(value != '\n') loop will probably run forever, writing past the end of the lines array until you get a segmentation fault. value, which is controlling when the loop will terminate, is never modified (also it isn't initialized, making it start with an arbitrary value). The getNum() function, which probably is supposed to modify value, gets a copy of the integer passed as a parameter and then modifies this copy. The original value is never changed.
If you want the function to change the value variable you have to use a pointer that points to value and that is used to modify that variable:
int getNum(int *value, ...) {
*value = 5;
...
}
l=getNum(&value, infile);
Also it is a little dubious that value, an integer variable, is assigned and compared against '\n', a character literal. Are you sure you want to use the integer value of '\n' as a termination condition of your loop?
While not a direct answer, I'd recommend sticking a number of printf statements in at random spots; that will let you narrow down the exact point of the crash relatively quickly. Move them around until you have two printfs bracketing a single line of code that you then know to be the crashing culprit, which will let you diagnose better.

Resources