trying to get the number of lines in a text file. and i get this error that i havent seen before.
the error says debug assertion failed. expression c>=-1 && c <=255
void get_lines(FILE* fp, int* plines){
int i=0;
char c;
int number_of_conversions;
number_of_conversions = fscanf(fp, "%c", &c);
while (number_of_conversions != EOF && number_of_conversions != 0 ){
number_of_conversions = fscanf(fp, "%c", &c);
if (c == '\n' ){
i++;
}
}
*plines = i;
}
The code you presented does not correspond to the error message you presented. The error message is related to an assertion somewhere else in your source code, having this form:
assert(c>=-1 && c <=255);
The problem it signals is probably related to variable c in the scope where that assertion appears having a signed character type (signed char, or char on a system where default char is signed). In all likelihood, the essentials of the code involved boil down to something like this:
char c = getc(fp); /* DO NOT DO THIS */
assert(c>=-1 && c <=255);
That is a common error: getc() and getchar() return type int in order to be able to represent all possible values of type unsigned char, and -1. If you assign the result to a variable of character type, then
You may invoke undefined behavior in the event that the result is outside the range representable by type char (e.g. 128 - 255 on a system having 8-bit, signed default chars)
If the program happens to behave consistently (on which you cannot rely unless the character type in question is unsigned), you lose the ability to distinguish an error condition from valid data.
If the target character type is signed, then although the result behavior is undefined for some inputs, a reasonably likely actual behavior would be for c to take values less than -1 in some cases. In that event you could get an assertion failure. ("could" because nothing is certain when UB is involved.)
To avoid those issues, make sure to assign function results to variables of appropriate type, and in particular, assign the results of getc() and getchar() to a signed integer type at least as wide as int.
the problem is basically two things:
1) that a char cannot hold a negative int (EOF is -1, I.E a negative int)
2) fscanf() stops when it hits white space and a '\n' is white space.
Suggest: using:
int char c;
c = fgetc(fp);
an example program would be:
void get_lines(FILE* fp, int* plines){
int i=0;
int c = 0;
while( EOF != (c = fgetc(fp) ) ) // returns EOF on end of file or error
{
if (c == '\n' )
{
i++;
}
}
*plines = i;
} // end function: get_lines
However, this still has a bug when the text file does not end in a newline
Related
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
This question already has answers here:
Comparing unsigned char and EOF
(6 answers)
Closed 5 years ago.
I’m learning C using Xcode 8 and the compiler doesn’t run any code after a while- or for-loop executes. is this a bug? how can I fix it?
In the example provided below printf("code executed after while-loop"); never executes
#include <stdio.h>
int getTheLine(char string[]);
int getTheLine(char string[]) {
char character;
int index;
index = 0;
while ((character = getchar()) >= EOF) {
string[index] = character;
++index;
}
printf("code executed after while-loop");
return index;
}
int main(int argc, const char * argv[]) {
char string[100];
int length = getTheLine(string);
printf("length %d\n", length);
return 0;
}
getchar returns an int not a char, and comparison with EOF should be done with the != operator instead of the >= operator.
...
int character; // int instead of char
int index;
index = 0;
while ((character = getchar()) != EOF) { // != instead of >=
...
It's the >= EOF, which will let the condition be always true. The reason is that a "valid" result of getchar() will be a positive integer, and a "non-valid" result like end-of-file will be EOF, which is negative (cf. getchar()):
EOF ... integer constant expression of type int and negative value
Hence, any valid result from getchar will be >EOF, while the end-of-file-result will be ==EOF, such that >= EOF will always match.
Write != EOF instead.
Note further that you do not terminate your string by the string-terminating-character '\0', such that using string like a string (e.g. in a printf("%s",string)) will yield undefined behaviour (crash or something else probably unwanted).
So write at least:
while ((character = getchar()) != EOF) {
string[index] = character;
++index;
}
string[index]='\0';
Then there is still the issue that you may write out of bounds, e.g. if one enters more then 100 characters in your example. But checking this is now beyond the actual question, which was about the infinite loop.
The symbolic constant EOF is an integer constant, of type int. It's (usually) defined as a macro as -1.
The problem is that the value -1 as an (32-bit) int has the value 0xffffffff and as a (8-bit) char the same value would be 0xff. Those two values are not equal. Which in turn means that your loop condition will never be false, leading to an infinite loop.
The solution to this problem is that all standard functions that reads characters returns them as an int. Which means your variable character needs to be of that type too.
Important note: It's a compiler implementation detail if plain char is a signed or an unsigned type. If it is signed then a comparison to an int would lead to sign extension when the char value is promoted in the comparison. That means a signed char with the value 0xff would be extended to the int value 0xffffffff. That means if char is signed then the comparison would work.
This means that your compile have char as unsigned char. So the unsigned char value 0xff after promotion to int will be 0x000000ff.
As for why the value -1 becomes 0xffffffff is because of how negative numbers are usually represented on computers, with something called two's complement.
You also have another couple of flaws in your code.
The first is that since the loop is infinite you will go way out of bounds of the string array, leading to undefined behavior (and a possible crash sooner or later). The solution to this is to add a condition to make sure that index never reaches 100 (in the specific case of your array, should really be passed as an argument).
The second problem is that if you intend to use the string array as an actual string, you need to terminate it. Strings in C are actually called null terminated strings. That terminator is the character '\0' (equal to integer 0), and need to be put at the end of every string you want to pass to a standard function handling such strings. Having this terminator means that an array of 100 characters only can have 99 characters in it, to be able to fit the terminator. This have implications to the solution to the above problem. As for how to add the terminator, simply do string[index] = '\0'; after the loop (if index is within bounds of course).
i'm having a problem with comparisons using getchar() and file redirection.
I have a code that resembles this:
char result = getchar(); // getchar returns the next char in the file
int linecount = 0;
if (result == "\n") {
linecount++;
}
But I get a warning when compiling it. It says that I can't compare an int with a pointer, but from my understanding, result is a char and so is "\n", so I'm really confused. I can also use printf("%c", result") and it works fine, implying that result is a char. Does anyone know why I'm getting this error? Thanks! Also, running the code, linecount will always return 0 even if the first character in the file I'm using as my input is a newline.
You are comparing a char with a char *, that is, a string. "" (doublequoted) values are treated as strings in C, so your code should be
if (result == '\n') {
linecount++;
}
Alternatively, you could use strcmp or strncmp with the char casted to a pointer, but that's not necessary.
Do note that the size of a char is less than an int so the conversion from a char to int doesn't make you lose anything.
I can't figure out why my while loop won't work. The code works fine without it... The purpose of the code is to find a secret message in a bin file. So I got the code to find the letters, but now when I try to get it to loop until the end of the file, it doesn't work. I'm new at this. What am I doing wrong?
main(){
FILE* message;
int i, start;
long int size;
char keep[1];
message = fopen("c:\\myFiles\\Message.dat", "rb");
if(message == NULL){
printf("There was a problem reading the file. \n");
exit(-1);
}
//the first 4 bytes contain an int that tells how many subsequent bytes you can throw away
fread(&start, sizeof(int), 1, message);
printf("%i \n", start); //#of first 4 bytes was 280
fseek(message, start, SEEK_CUR); //skip 280 bytes
keep[0] = fgetc(message); //get next character, keep it
printf("%c", keep[0]); //print character
while( (keep[0] = getc(message)) != EOF) {
fread(&start, sizeof(int), 1, message);
fseek(message, start, SEEK_CUR);
keep[0] = fgetc(message);
printf("%c", keep[0]);
}
fclose(message);
system("pause");
}
EDIT:
After looking at my code in the debugger, it looks like having "getc" in the while loop threw everything off. I fixed it by creating a new char called letter, and then replacing my code with this:
fread(&start, sizeof(int), 1, message);
fseek(message, start, SEEK_CUR);
while( (letter = getc(message)) != EOF) {
printf("%c", letter);
fread(&start, sizeof(int), 1, message);
fseek(message, start, SEEK_CUR);
}
It works like a charm now. Any more suggestions are certainly welcome. Thanks everyone.
The return value from getc() and its relatives is an int, not a char.
If you assign the result of getc() to a char, one of two things happens when it returns EOF:
If plain char is unsigned, then EOF is converted to 0xFF, and 0xFF != EOF, so the loop never terminates.
If plain char is signed, then EOF is equivalent to a valid character (in the 8859-1 code set, that's ÿ, y-umlaut, U+00FF, LATIN SMALL LETTER Y WITH DIAERESIS), and your loop may terminate early.
Given the problem you face, we can tentatively guess you have plain char as an unsigned type.
The reason that getc() et al return an int is that they have to return every possible value that can fit in a char and also a distinct value, EOF. In the C standard, it says:
ISO/IEC 9899:2011 §7.21.7.1 The fgetc() function
int fgetc(FILE *stream);
If the end-of-file indicator for the input stream pointed to by stream is not set and a
next character is present, the fgetc function obtains that character as an unsigned char converted to an int ...
If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the end-of-
file indicator for the stream is set and the fgetc function returns EOF.
Similar wording applies to the getc() function and the getchar() function: they are defined to behave like the fgetc() function except that if getc() is implemented as a macro, it may take liberties with the file stream argument that are not normally granted to standard macros — specifically, the stream argument expression may be evaluated more than once, so calling getc() with side-effects (getc(fp++)) is very silly (but change to fgetc() and it would be safe, but still eccentric).
In your loop, you could use:
int c;
while ((c = getc(message)) != EOF) {
keep[0] = c;
This preserves the assignment to keep[0]; I'm not sure you truly need it.
You should be checking the other calls to fgets(), getc(), fread() to make sure you are getting what you expect as input. Especially on input, you cannot really afford to skip those checks. Sooner, rather than later, something will go wrong and if you aren't religiously checking the return statuses, your code is likely to crash, or simply 'go wrong'.
There are 256 different char values that might be returned by getc() and stored in a char variable like keep[0] (yes, I'm oversummarising wildly). To detect end-of-file reliably, EOF has to have a value different from all of them. That's why getc() returns int rather than char: because a 257th distinct value for EOF wouldn't fit into a char.
Thus you need to store the value returned by getc() in an int at least until you check it against EOF:
int tmpc;
while( (tmpc = getc(message)) != EOF) {
keep[0] = tmpc;
...
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. ...