I am trying to run a simple C program that takes a file of random floating point values, automatically identify the length of the file and use the length to perform further computation. However, my compiler either hangs or I get erroneous results. Here is my code
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>
int main() {
FILE *fptr;
int count = 0; // Line counter (result)
char ch; // To store a character read from file
if ((fptr = fopen("C:\\Users\\Evandovich\\Desktop\\White_Noise.txt", "r"))
== NULL) {
printf("Error! opening file");
// Program exits if the file pointer returns NULL.
exit(1);
}
// Extract characters from file and store in character ch
for (ch = getc(fptr); ch != EOF; ch = getc(fptr)) {
if (ch == '\n') // Increment count if this character is newline
count = count + 1;
}
printf("The file has %d lines\n ", count);
// use the value of "count" to be the length of the array.
char arrayNum[count];
char *eptr;
double result, result1[count];
for (int i = 0; i < count; i++) {
fscanf(fptr, "%s", &arrayNum[i]);
/* Convert the provided value to a double */
result = strtod(&arrayNum[i], &eptr);
result1[i] = pow(result, 2);
printf("value %f\n", result1[i]);
}
fclose(fptr);
return 0;
}
What particularly is the error? Your input is well appreciated.
INPUT file (N.txt) contains
0.137726
0.390126
-0.883234
0.006154
-0.170388
-1.651212
0.510328
OUTPUT
The file has 7 files
value 0.000000
value 0.000000
value 0.000000
value 0.000000
value 0.000000
value 0.000000
value 0.000000
Expected
The file has 7 files
value 0.018968
value 0.152198
value 0.780102
value 0.000038
value 0.029032
value 2.726501
value 0.260435
At least these problems:
At end of file
Code fails as it attempts to read the floating point text from the end of the file. #ErlingHaaland
After determining line count, add:
rewind(fptr);
Convoluted read
Read a line with fgets(). Avoid "%s" without a width limit - it might overflow. Use a line buffer that is based on max line length, not line count. Convert to a double by starting at the begining of the line.
#define LINE_SIZE 100
char arrayNum[LINE_SIZE];
if (fgets(arrayNum, sizeof arrayNum, fptr) == NULL) {
break;
}
result = strtod(arrayNum, &eptr);
Check conversion
errno = 0;
result = strtod(arrayNum, &eptr);
if (arrayNum == eptr || errno) {
break;
}
Too small a type
int getc(FILE *) typically returns 257 different values: EOF and [0...UCHAR_MAX]. Saving that in a char loses information. Save in an int.
Line count at risk
May be off by 1 as the last line might not have a '\n': #Adrian McCarthy.
Instead count line beginnings.
size_t count = 0;
int previous = '\n';
int ch;
while ((ch = getc(fptr) != EOF) {
if (previous == '\n') {
count++;
}
previous = ch;
}
printf("The file has %zu lines.\n ", count);
// Also
rewind(fptr);
A couple problems:
getc returns the value of the next char as an int or the special value EOF. Since your variable ch is a char, the EOF value may not be recognizable in which case the line counting loop might never end.
You define arrays whose size is determined by a run time variable count. I use C++ regularly, but I have written in C in a very long time. When I did write in C, the size of arrays had to be determined at compile time. Perhaps this is a newer feature of C? I'd check. Make sure you have compiler warnings enabled.
count might be short one line if the last line of the file doesn't end with '\n'. On Posix systems, a line is supposed to end with a newline character. On Windows, it's common for the newline sequence (typically CR+LF) to be treated as a line separator. Thus files may or may not end with the newline sequence at the end of the last line.
arrayNum is an array of count characters rather than an array of pointers to character strings.
The fastest, most efficient, and safest way to get file size is to ask the operating system via stat():
struct stat statbuf;
stat("C:\\Users\\Evandovich\\Desktop\\White_Noise.txt", &statbuf);
statbuf.st_size; /* The file size in bytes */
Related
I need to output the sum of the numbers that are inside of a sentence.
For example :
input: abc3x casa2 y34zq
output : 3+2+3+4 = 12
I need to read all the sentences include the space to do this, but my loop with getchar doesn't work. Can help me to find the problem?
int main() {
int i = 0;
int somma = 0;
char s[MAX];
printf("inserisci la stringa : ");
scanf("%s",s);
while((s[i] = getchar()) != '\n'){
i++;
if(s[i]>'0' && s[i]<'9'){
somma+= (int)s[i]-(int)'0';
}
}
printf("la somma è = %d", somma);
}
I don’t have to use getchar. I would prefer to use fgets because I know that fgets can read the entire line including the space.
Since you are ok with using fgets() you can read the entire line and then use isdigit() to find the numbers.
FILE *fp;
fp = fopen("file.txt" , "r");
if(fp == NULL) {
perror("Error opening file");
return(-1);
}
char line[MAX];
if( fgets(line, MAX, fp) == NULL ) { // Read entire line
perror("Error reading file");
return -1;
}
int sum = 0;
int len = strlen(line);
for (int i = 0; i < len; i++) {
if (isdigit( (unsigned char)line[i] )) { // cast handles negative values of line[i]
sum += line[i] - '0'; // Add integer value to sum
}
}
The basic idea is the same, only this loops over a string directly instead of trying to read it with getchar() at each step.
There are two ways to solve your problem.
Get entire string in one go from user
To read entire string, you can use scanf as you are using it. It will store entire string in array (s in your case) and then you can parse this array and peform operations as you are doing. Here limitation would be length of string. You can accept string of the MAX size only as your array is of that much size. If you are okay with this, then your code is correct. All you need to do is remove that getChar() from while.
Read one character at a time.
Alternatively, you can read one character at a time from user and immediately perform operations on that character. In that case, you don't need to declare array. One character variable is sufficient and you can go on accepting data from user. In this case, discard the scanf() and in your while(), accept getChar() output in one character and perform your operation.
P.S. There's one small bug in your while() which will give you incorrect result in few cases.
Empty lines also should be removed if they are duplicates. If line has escape sequences (like \t), it's different than empty line. Code below is deleting too many lines, or sometimes leave duplicates. How to fix this?
#include <stdio.h>
#include <stdlib.h>
int main()
{
char a[6000];
char b[6000];
int test = 0;
fgets(a, 6000, stdin);
while (fgets(b, 6000, stdin) != NULL) {
for (int i = 0; i < 6000; i++) {
if (a[i] != b[i]) {
test = 1;
}
}
if (test == 0) {
fgets(b, 6000, stdin);
} else {
printf("%s", a);
}
int j = 0;
while (j < 6000) {
a[j] = b[j];
j++;
}
test = 0;
}
return 0;
}
Your logic is mostly sound. You are on the right track with your train of thought:
Read a line into previous (a).
Read another line into current (b).
If previous and current have the same contents, go to step 2.
Print previous.
Move current to previous.
Go to step 2.
This still has some problems, however.
Unnecessary line-read
To start, consider this bit of code:
while(fgets(b,6000,stdin)!=NULL) {
...
if(test==0) {
fgets(b,6000,stdin);
}
else {
printf("%s",a);
}
...
}
If a and b have the same contents (test==0), you use an unchecked fgets to read a line again, except you read again when the loop condition fgets(b,6000,stdin)!=NULL is evaluated. The problem is that you're mostly ignoring the line you just read, meaning you're moving an unknown line from b to a. Since the loop already reads another line and checks for failure appropriately, just let the loop read the line, and invert the if statement's equality test to print a if test!=0.
Where's the last line?
Your logic also will not print the last line. Consider a file with 1 line. You read it, then fgets in the loop condition attempts to read another line, which fails because you're at the end of the file. There is no print statement outside the loop, so you never print the line.
Now what about a file with 2 lines that differ? You read the first line, then the last line, see they're different, and print the first line. Then you overwrite the first line's buffer with the last line. You fail to read another line because there aren't any more, and the last line is, again, not printed.
You can fix this by replacing the first (unchecked) fgets with a[0] = 0. That makes the first byte of a a null byte, which means the end of the string. It won't compare equal to a line you read, so test==1, meaning a will be printed. Since there is no string in a to print, nothing is printed. Things then continue as normal, with the contents of b being moved into a and another line being read.
Unique last line problem
This leaves one problem: the last line won't be printed if it's not a duplicate. To fix this, just print b instead of a.
The final recipe
Assign 0 to the first byte of previous (a[0]).
Read a line into current (b).
If previous and current have the same contents, go to step 2.
Print current.
Move current to previous.
Go to step 2.
As you can see, it's not much different from your existing logic; only steps 1 and 4 differ. It also ensures that all fgets calls are checked. If there are no lines in a file, nothing is printed. If there is only 1 line in a file, it is printed. If 2 lines differ, both are printed. If 2 lines are the same, the first is printed.
Optional: optimizations
Instead of checking all 6000 bytes, you only check up to the first null byte in either string since fgets will automatically add one to mark the end of the string.
Faster still would be to add a break statement inside the if statement of your for loop. If a single byte doesn't match, the entire line is not a duplicate, so you can stop comparing early—a lot faster if only byte 10 differs in two 1000-byte lines!
#include <stdio.h>
#include <string.h>
int main(void)
{
char buff[2][6000];
unsigned count=0;
char *prev=NULL
, *this= buff[count%2]
;
while( fgets(this, sizeof buff[0] , stdin)) {
if(!prev || strcmp(prev, this) ) { // first or different
fputs(this, stdout);
prev=this;
count++;
this=buff[count%2];
}
}
fprintf(stderr, "Number of lines witten: %u\n", count);
return 0;
}
There are few problems in your code, like :
for(int i=0; i<6000; i++) {
if(a[i]!=b[i]) {
test=1;
}
}
In this loop, every time the whole buffer will be compared character by character even if it finds if(a[i]!=b[i]) for some value of i. Probably you should break loop after test=1.
Your logic will also not work for a file with just 1 line as you are not printing line outside the loop.
Another problem is fixed length buffer of size of 6000 char.
May you can use getline to solve your problem. You can do -
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char * line = NULL;
char * comparewith = NULL;
int notduplicate;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, stdin)) != -1) {
((comparewith == NULL ) || (strcmp (line, comparewith) != 0)) ? (notduplicate = 1) : (notduplicate = 0);
if (notduplicate) {
printf ("%s\n", line);
if (comparewith != NULL)
free(comparewith);
comparewith = line;
line = NULL;
}
}
if (line)
free (line);
if (comparewith)
free (comparewith);
return 0;
}
An important point to note:
getline() is not in the C standard library. getline() was originally GNU extension and standardized in POSIX.1-2008. So, this code may not be portable. To make it portable, you'll need to roll your own getline() something like this.
Here is a much simpler solution that has no limitation on line length:
#include <stdio.h>
int main(void) {
int c, last1 = 0, last2 = 0;
while ((c = getchar()) != EOF) {
if (c != '\n' || last1 != '\n' || last2 != '\n')
putchar(c);
last2 = last1;
last1 = c;
}
return 0;
}
The code skips sequences of more than 2 consecutive newline characters, hence it removes duplicate blank lines.
here is my current code:
int num = 0;
char c = '#';
scanf("%d",&num);
do{
for (int i=0;i<num;i++){
printf("%c",c);
}
printf("\n");
}
while (scanf("%d", &num) == 1);
How would I have it so that if the user doesn't enter anything, that the program won't spit out a newline?
Any help is appreciated, thank you!
This code should work for what you want to do :
#include <stdio.h>
int main()
{
int num = 0;
char c = '#';
char readLine[50];
while ((fgets(readLine, sizeof readLine, stdin) != NULL) && sscanf(readLine, "%d", &num) == 1)
{
for (int i=0;i<num;i++){
printf("%c",c);
}
printf("\n");
fflush(stdout);
}
return 0;
}
The behaviour of this code is the following : fgets will read anything you enter in the standard stream (stdin), and put it in the readLine array. The program will then try to read the number which is in your readLine variable and put it in your num variable with the sscanf function. If a number is read, the program will execute the behaviour you did present in your question (writing a # character "num" times), and go back to the beginning of the loop. If anything else than a number has been read, the loop is stopped.
In general, avoid scanf. It's very easy to leave yourself with unprocessed cruft on the input stream. Instead, read the whole line and then use sscanf (or something else) to process it. This guarantees that you won't get stuck with a partially read line, those are hard to debug.
I prefer getline to fgets to read lines. fgets requires you to guess how long the input might be, and input might get truncated. getline will allocate the memory to read the line for you avoiding buffer overflow or truncation problems.
NOTE: getline is it's not a C standard function, but a POSIX one and fairly recent (2008), though it was a GNU extension well before that. Some older compilers may not have it.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char c = '#';
char *line = NULL;
size_t linelen = 0;
/* First read the whole line */
while( getline(&line, &linelen, stdin) > 0 ) {
/* Then figure out what's in it */
long num = 0;
if( sscanf(line, "%ld", &num) > 0 ) {
for( int i = 0; i < num; i++ ) {
printf("%c", c);
}
printf("\n");
}
}
free(line);
return 0;
}
if( sscanf(line, "%ld", &num) > 0 ) { will ignore any line that does not match any part of the pattern, such as a blank line or a line full of words, by checking how many things matched. Yet it will still handle 0 as a valid input.
$ ./test
foo
bar
foo123
12
############
1
#
0
2
##
I also moved num inside the loop to guarantee it's reinitialized each iteration, and on the general principle of putting your variables in minimum scopes to avoid interference. And I upgraded it to a long int better able to handle the unpredictably large numbers users might type in.
Here is how I have done input parsing over the years using the fgets() and sscanf() functions. I don't write c++ much, and if I can I keep code within old style ansi C then I do.
The fgets and sscanf functions from the stdio.h library are universal and are always available on any platform.
For a character array used to read in anything, I generally set LINE_SIZE to 256 or 512 even if I know typically the line to be read is 80 characters or less. With any computer today having over 1GB of RAM, not worth worrying about allocating an extra 500 or so bytes. Obviously, if you have no idea how long the input line is then you either have to:
guess at what LINE_SIZE should be set to and not worry about it
or verify a newline character is present in line[] prior to a null character after calling fgets().
# include <stdio.h>
# define LINE_SIZE 256
int main ( int argc, char *argv[] )
{
FILE *fp;
char line[LINE_SIZE];
int nn;
int value;
fp = fopen( "somefile", "r" );
fgets( line, LINE_SIZE, fp );
/*
this way to read from standard input (i.e. the keyboard)
using fgets with stdin prevents compiler warning when using
deprecated gets function
fgets( line, LINE_SIZE, stdin );
*/
if ( line[0] != '\n' )
{
/* definitely not a blank line */
nn = sscanf( line, "%d", &num );
if ( nn == 1 )
{
/* some number placed into num variable that met the
%d conversion for the sscanf function
*/
}
}
return 0;
I'm trying to go through a file line by line (each line is no more than 50 characters), shift each character by 10 or -10 (to encrypt and decrypt) and then print the shifted string where the old string was. But I'm getting some really funny output.
heres the code:
#include <stdio.h>
int main(void){
FILE *fp;
fp=fopen("tester.csv","r+");
Encrypt(fp); // I call decrypt here when I test it.
fclose(fp);
}
int Encrypt(FILE *fp){
int offset=10;
Shift(fp, offset);
}
int Decrypt(FILE *fp){
int offset= -10;
Shift(fp, offset);
}
int Shift(FILE *fp, int offset){
char line[50],tmp[50], character;
long position;
int i;
position = ftell(fp);
while(fgets(line,50,fp) != NULL){
for(i=0;i<50;i++){
character = line[i];
character = (character+offset)%256;
tmp[i] = character;
}
fseek(fp,position,SEEK_SET);
fputs(tmp, fp);
position = ftell(fp);
}
}
so if tester.csv originally reads
this, is, a, test
running the program produces
~rs}6*s}6*k6*~o}~
êñv[ ‰
this, is, a, test
fputs(tmp, fp);
fputs writes the bytes until the terminating 0 byte.
while(fgets(line,50,fp) != NULL){
for(i=0;i<50;i++){
character = line[i];
character += offset;
tmp[i] = character;
}
you shift 50 chars, regardless of how long the line that you read in was, and thus most of the time, there is no 0-byte in the tmp buffer, thus fputs often writes at least 50 bytes, some of which have nothing to do with what was in the file at that place, and beyond the buffer, which invokes undefined behaviour and might cause a crash.
You should check for the terminating 0-byte in the loop, probably even stopping at the newline is a good idea.
while(fgets(line,50,fp) != NULL){
for(i = 0; i < 50 && line[i] != 0 && line[i] != '\n'; i++){
character = line[i];
character += offset;
tmp[i] = character;
}
Note: the loop body would simpler be line[i] += offset;.
Try using GDB to Debug your program as it encrypts.
Compile with:
gcc -g -Wall YOURPROGRAM.cxx
Run gdb:
gdb YOURPROGRAM.cxx
Set a BreakPoint:
Break at line 3: break 3
Debug your Program: run
You can step through each line of code using step and next, and print out variables at each point using print VARIABLENAME. It's a powerful program, and really helpful in debugging.
You should probably not be using the line-oriented fgets() and fputs() since you could get NUL '\0' characters in the output data on encryption, and in the input data on decryption (and newlines will be . Use fread() and fwrite(). Make sure you handle the right number of characters too; fgets() might not return 49 characters and a NUL; the line might be shorter, and you don't want to process the NUL anyway.
/* stringlength
* input: str, pointer to a string
* output: integer representing the length of string str,
* not counting the terminating character.
*
* You may NOT call ANY functions within this function.
*/
int stringlength(char *str)
{
// count the number of characters in str
int count=0,k;
for (k=0; str[k] != '\0';k++)
count++;
return count;
}
/* countchars
* inputs: character c, string str
* output: The number of instances of c in the string str
* You may not call ANY function calls within this function.
*/
int countchars(char c, char *str)
{
// count the number of times c is found in str
int k,count=0;
for (k=0;str[k]=='\0';k++)
{
if (str[k] == c)
count++;
else;
}
return count;
}
/* countlines
* input: char *filename - string containing the filename
* output: integer representing the number of lines in the file
*/
int countlines(char *filename)
{
// count the number of lines in the file called filename
FILE *f = fopen(filename,"r");
char ch;
int lines=0;
f = fopen(filename,"r");
do{
ch = fgetc(f);
if( ch == '\n')
lines++;
}while( ch != EOF );
return lines;
}
I need help with these three different functions that I am implementing in my program. I am a beginner so go easy on me, the countlines function is giving me the most trouble. If anyone could explain why not or why these functions will work, it would be greatly appreciated.
There are a number of problems in countlines():
You open the file twice, but overwrite the first FILE * value with the second, so there's no way you can close it. This is a minor problem.
The major problem is that the function fgetc() returns an int, not a char. In particular, EOF is a value different from every char.
The code does not close the file before returning. Generally, if you open a file in a function, then you should close it. If you don't, you have to pass the file pointer back to the calling code so that it can close it.
The do ... while loop is seldom correct for an input loop (a while loop testing at the top is almost always much cleaner and clearer) but at least you weren't using feof().
int countlines(char *filename)
{
FILE *fp = fopen(filename,"r");
int ch;
int lines = 0;
if (fp == 0)
return lines;
while ((ch = fgetc(fp)) != EOF)
{
if (ch == '\n')
lines++;
}
fclose(fp);
return lines;
}
When you use char instead, one of two things happens:
If your char type is signed, then a real character (often ÿ — y-umlaut, U+00FF, LATIN SMALL LETTER Y WITH DIAERESIS) also matches EOF so you can stop reading before you reach end of file.
If your char type is unsigned, no value will ever match EOF so the loop will never stop.
In stringlength(), you have two variables count and k that are carefully kept at the same value; you only need one of the two.
Apart from raggedy indentation (endemic in the code shown — and definitely something to be avoided), and the unnecessary and pointless else; which does absolutely nothing, the code for countchars() looks OK (late addition) ... has the condition in the for loop inverted; it should be str[k] != '\0', of course.