Why these c code not working? Whats wrong with these? - c

#include < stdio.h >
#include < string.h >
int main()
{
unsigned char a;
FILE *P;
P=fopen("mola.txt","r");
while((a=getc(P))!=EOF)
printf("%c",a);
}
Whats wrong with these code? When I compile it gives warning "comparison is always true due to limited range of data type." What does that warning mean?

You are storing the result of getc in a char. It should be an int. There's also a C FAQ on it. Also you should check the return value of the fopen.
P=fopen("mola.txt","r");
if (NULL == P) {
perror("fopen"):
}
Also the while looks fishy. Try indenting ?
while((a=getc(P)) != EOF)
printf("%c",a);

It means just what it says
comparison is always true due to limited range of data type.
The range of the data type in question (the a, which is unsigned char) is from 0 to 255 (really UCHAR_MAX);
The EOF value is -1
You are comparing a (from 0 to 255) with -1
(a != -1)
the condition will always be true

Try:
#include <stdio.h>
#include <string.h>
int main()
{
int a;
FILE *P;
P=fopen("tryit2.c","r");
while(EOF != (a = fgetc(P))) {
printf("%c",a);
}
}
You had two problems "getc()" returns an integer not a character. And the while statement had some weird side effects in the original order.

It means the loop will fell into Infinite loop not allowing the program to exit when at a=getc(p).

Related

C Program to count number of alphabets in a word giving error

Following is the code:
#include<stdio.h>
int main()
{
int alpha = 0, input;
while((input = getchar() != EOF))
{
if(isalpha(input))
alpha++;
}
printf("Num of alpha is %d", alpha);
return(0);
}
I'm getting error as
isalpha was not declared in this scope
when compiled on DevC++ compiler.
isalpha() is declared in ctype.h
It might be good to know that even though the argument to isalpha (and all the isxxx family functions) is an int, the behavior is undefined if the argument is negative. So if you're on a machine where char is signed as default, you might run into trouble unless you cast first. Like this:
char c;
// Some code
if(isalpha((unsigned char) c)) {
It can be a good habit to always cast for these functions. However, do NOT use casting as a goto for silencing warnings. It can easily hide errors. In most cases when a cast is needed, your code is wrong in some other way. Rant about casting
Another pitfall with these functions (and many other C functions that returns an int as a Boolean) is that they are required to return zero on false, but are allowed to return any non-zero value on true. So a check like this is complete nonsense:
if( isalpha(c) == 1 )
Instead do any of these:
if( isalpha(c) != 0 ) // If not zero
if( isalpha(c) ) // Use directly as Boolean (recommended)
if( !! isalpha(c) == 1) // Double negation turns non zero to 1

How to check an edge case in taking command line argument in C and evaluating to int or double?

So I have an assignment to figure out whether a number on the command line is either an integer or a double.
I have it mostly figured it out by doing:
sscanf(argv[x], "%lf", &d)
Where "d" is a double. I then cast it to an int and then subtract "d" with itself to check to see if it is 0.0 as such.
d - (int)d == 0.0
My problem is if the command line arguments contains doubles that can be technically classified as ints.
I need to classify 3.0 as a double whereas my solution considers it an int.
For example initializing the program.
a.out 3.0
I need it to print out
"3.0 is a double"
However right now it becomes
"3 is an int."
What would be a way to check for this? I did look around for similar problems which led me to the current solution but just this one edge case I do not know how to account for.
Thank you.
For example, a way like this:
#include <stdio.h>
int main(int argc, char *argv[]){
if(argc != 2){
puts("Need an argument!");
return -1;
}
int int_v, read_len = 0;
double double_v;
printf("'%s' is ", argv[1]);
//==1 : It was able to read normally.
//!argv[1][read_len] : It used all the argument strings.
if(sscanf(argv[1], "%d%n", &int_v, &read_len) == 1 && !argv[1][read_len])
puts("an int.");
else if(sscanf(argv[1], "%lf%n", &double_v, &read_len) == 1 && !argv[1][read_len])
puts("a double.");
else
puts("isn't the expected input.");
}
To test if a string will covert to a int and/or double (completely, without integer overflow, without undefined behavior), call strtol()/strtod(). #Tom Karzes
The trouble with a sscanf() approach is that the result is undefined behavior (UB) on overflow. To properly detect, use strtol()/strtod().
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
bool is_int(const char *src) {
char *endptr;
// Clear, so it may be tested after strtol().
errno = 0;
// Using 0 here allows 0x1234, octal 0123 and decimal 1234.
// or use 10 to allow only decimal text.
long num = strtol(src, &endptr, 0 /* or 10 */);
#if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
if (num < INT_MIN || num > INT_MAX) {
errno = ERANGE;
}
#endif
return !errno && endptr > src && *endptr == '\0';
}
bool is_double(const char *src) {
char *endptr;
// Clear, so it may be tested after strtod().
strtod(src, &endptr);
// In this case, detecting over/underflow IMO is not a concern.
return endptr > src && *endptr == '\0';
}
It is not entirely clear what the specific expectations are for your program, but it has at least something to do with the form of the input, since "3.0" must be classified as a double. If the form is all it should care about, then you should not try to convert the argument strings to numbers at all, for then you will run into trouble with unrepresentable values. In that case, you should analyze the character sequence of the argument to see whether it matches the pattern of an integer, and if not, whether it matches the pattern of a floating-point number.
For example:
int main(int argc, char *argv[]) {
for (int arg_num = 1; arg_num < argc; arg_num++) {
char *arg = argv[arg_num];
int i = (arg[0] == '-' || arg[0] == '+') ? 1 : 0; // skip any leading sign
// scan through all the decimal digits
while(isdigit(arg[i])) {
++i;
}
printf("Argument %d is %s.\n", arg_num, arg[i] ? "floating-point" : "integer");
}
}
That makes several assumptions, chief among them:
the question is strictly about form, so that the properties of your system's built-in data types (such as int and double) are not relevant.
each argument will have the form of either an integer or a floating-point number, so that eliminating "integer" as a possibility leaves "floating-point" as the only alternative. If "neither" is a possibility that must also be accommodated, then you'll also need to compare the inputs that do not have integer form to a pattern for floating-point numbers, too.
only decimal (or smaller radix) integers need be accommodated -- not, for example, hexadecimal inputs.
Under those assumptions, particularly the first, it is not just unnecessary but counterproductive to attempt to convert the arguments to one of the built-in numeric data types, because you would then come to the wrong conclusion about arguments that, say, are not within the bounds of representable values for those types.
For example, consider how the program should classify "9000000000". It has the form of an integer, but supposing that your system's int type has 31 value bits, that type cannot accommodate a value as large as the one the string represents.
int main (int argc,char *argv[])
{
if(argc==2)
{
int i;
double d;
d=atof(argv[1]);
i=atoi(argv[1]);
if(d!=i)
printf("%s is a double.",argv[1]);
else if(d==i)
printf("%s is an int.",argv[1]);
}
else
printf("Invalid input\n");
return 0;
}
You must add #include <stdlib.h>

Reading character by character from a file in C

I wrote the following program :
int main(){
char str[500],c;
FILE *f1=fopen("input.txt","r");
FILE *f2=fopen("output.txt","w");
while(c=fgetc(f1)!=EOF)
fputc(toupper(c),f2);
fclose(f1);
}
I was not getting the desired result though.
I rewrote the code using a do while loop.
int main(){
char str[500];
FILE *f1=fopen("input.txt","r");
FILE *f2=fopen("output.txt","w");
char c;
do
{
fputc(toupper(c),f2);
c=fgetc(f1);
}while(c!=EOF);
}
I figured out that the reason the first code fails is because in the while loop
while(c=fgetc(f1)!=EOF), we cannot guarantee that the left part of != is evaluated first and hence the results are not proper. Is this correct the explanation?
Yes you are correct; in your first code your while loop is written wrongly:
while(c=fgetc(f1)!=EOF)
Should be:
while((c=fgetc(f1))!=EOF)
// ^ ^ added parenthesis
Because the precedence of operator != is greater than = operator in conditional expression c=fgetc(f1)!=EOF, the first returned the result of comparing the value from fgetc() with EOF (either 0 or 1) and assigned that to c. (That means simply c=fgetc(f1)!=EOF expression is equivalent to c=(fgetc(f1)!=EOF) and this is not what you need.)
You need () to overwrite precedence as I suggested.
But you have second thing to improve that is c variable must be an int (not char) in order to hold an EOF-value.
A very good Read: Definition of EOF and how to use it effectively
I will add a little why c should be int, not char. Suppose you write
#include <stdio.h>
#include <ctype.h>
#include <locale.h>
int main(){
setlocale(LC_ALL,"");
FILE *f1=fopen("input.txt","r");
FILE *f2=fopen("output.txt","w");
char c;
while(EOF != (c=fgetc(f1))){
if(isalpha(c)) c = toupper(c);
fputc(c,f2);
}
return 0;
}
And your input.txt is
some text
Некоторый текст
Ъ - on this letter program will stop
in KOI8-R symbol Ъ have code 255 == -1 (when you use char).
That's why in case of using char instead of int will give your output.txt with only that text:
SOME TEXT
НЕКОТОРЫЙ ТЕКСТ
As for non-working code with parentheses: c=fgetc(f1)!=EOF could be denote by compiler as c = (fgetc(f1)!=EOF), that's why it's better always to add parentheses.
I recommend you to use flags -Wall -Werror when compiling your applications. In that case "forgetting" of parentheses would give you an error:
11.c: In function 'main':
11.c:9:2: error: suggest parentheses around assignment used as truth value [-Werror=parentheses]
cc1: all warnings being treated as errors

Cesar Cipher out of bounds in Array

Guys i found this caesar cipher code in some site.... But when i run it its showing segmentation fault in online compilers..but in c compiler tat i'm using its showing processor fault... can anyone pls point out the wrong in this code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define caesar(x) rot(13, x)
#define decaesar(x) rot(13, x)
#define decrypt_rot(x, y) rot((26-x), y)
void rot(int c, char *str)
{
int l = strlen(str);
const char *alpha[2] = { "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"};
int i;
for (i = 0; i < l; i++)
{
if (!isalpha(str[i]))
continue;
str[i] = alpha[isupper(str[i])][((int)(tolower(str[i])-'a')+c)%26];
}
}
int main()
{
char str[] = "This is a top secret text message!";
printf("Original: %s\n", str);
caesar(str);
printf("Encrypted: %s\n", str);
decaesar(str);
printf("Decrypted: %s\n", str);
return 0;
}
Your code is correct except for one detail, which might be confusing for a newbie.
It is ok to assume that the function isupper() returns a boolean value 1 or 0, but if you check the documentation it says A value different from zero (i.e., true) if indeed c is an uppercase alphabetic letter. Zero (i.e., false) otherwise.
This and the fact that isupper() is returning an int and not a _Bool is causing the problem.
int isupper ( int c );
When returning true isupper() might return any non_zero value. In my case it returns 8 ( a specific bit-field ). Probably the same in yours.
All you have to do is cast the return of isupper() to _Bool
printf("%d %d" ,(_Bool)isupper('A') , ((int)(tolower(str[i])-'a')+c)%26 ) ;
The problem is most likely your use of isupper as index. It's not guaranteed to return 1 for true values, just that it will return "true" (which may be any non-zero value).
You can solve this by using the ternary expression:
alpha[isupper(str[i]) ? 1 : 0][...]
In the first iteration of your loop, you are trying to write to alpha[256][6], (isupper does not always return 0 or 1)
isupper returns: A value different from zero (i.e., true) if indeed c is an
uppercase alphabetic letter. Zero (i.e., false) otherwise.
alpha[isupper(str[i]) != 0][...] will do the trick
Also note that you should always cast the argument you pass to
isupper(), isalnum(), etc. to unsigned char

Warning: comparison is always true due to limited range of data type

I'm testing this function that's supposed to read input from the user but it throws me a segmentation fault
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_STRING_LENGTH 10
int
readinput(char *input)
{
int c;
int i=0;
while((c=getchar()) != EOF && c != '\n') //Here is where the warning occurs.
{
input[i]=c;
i++;
}
input[i]=0;
if(strlen(input)>0)
{
if(isalpha(input[0]) && input[1]=='-' && isalpha(input[2]) && strlen(input)==3)
return 0;
else if(!strcmp(input, "quit"))
return 1;
else if(!strncmp(input, "save ", 5))
return 2;
else if(!strcmp(input, "undo"))
return 3;
}
return -1;
}
int main()
{
char *str;
printf("write a string\n");
int nr=readinput(str);
printf("%d\n", nr);
printf("%s\n", str);
return 0;
}
I did notice the stupid error I made, but still, segmentation fault, why?
This is because EOF is defined (in my compiler) as -1 and char is unsigned byte. so it is always !=
c != '/n' is wrong
change it to
c != '\n'
c != '/n' should be c != '\n'
\ is an escape character which indicates, in the case where it is followed by n, a newline. /n will be treated as two distinct characters, which cannot properly be compared to a single char variable.
As for you segmentation fault, you'll need to allocate some space for str in your main function:
char* str = malloc(sizeof(char)*MAX_STRING_LENGTH);
or
char str[MAX_STRING_LENGTH];
but you'll also have to ensure you don't try to read a string that has more characters than your str array can hold.
It faults because you never allocated space for str and it points to a random location which causes readinput to try to store data in a place that doesn't exist.
The segmentation fault arises because you've passed an uninitialized pointer to the function readinput(). You need to do something like:
char str[4096];
int nr = readinput(str);
You should pass in a length of the array so that the called code can verify that it does not overflow its boundaries. Or you can live dangerously and decide that 4096 is big enough, which it probably will be until someone is trying to break your program deliberately.
The original compiler warning was because the multi-character constant '/n' has a value (of type int) which is outside the range of values that can be stored in a char, so when c is promoted to int, the != comparison with the (implementation-defined) value of '/n' is bound to be true. Hence the warning:
Warning: comparison is always true due to limited range of data type
All multi-character character constants have implementation-defined values. There are no portable multi-character character constants.
ISO/IEC 9899:2011 §6.4.4.4 Character constants
¶10 ... The value of an integer character constant containing more than one character (e.g.,
'ab'), or containing a character or escape sequence that does not map to a single-byte
execution character, is implementation-defined. ...

Resources