So I have to write a program that prompts the user to enter the name of a file, using a pointer to an array created in main, and then open it. On a separate function I have to take a user defined string to a file opened in main and return the number of lines in the file based on how many strings it reads in a loop and returns that value to the caller.
So for my first function this is what I have.
void getFileName(char* array1[MAX_WIDTH])
{
FILE* data;
char userIn[MAX_WIDTH];
printf("Enter filename: ");
fgets(userIn, MAX_WIDTH, stdin);
userIn[strlen(userIn) - 1] = 0;
data = fopen(userIn, "r");
fclose(data);
return;
}
For my second function I have this.
int getLineCount(FILE* data, int max)
{
int i = 0;
char *array1[MAX_WIDTH];
if(data != NULL)
{
while(fgets(*array1, MAX_WIDTH, data) != NULL)
{
i+=1;
}
}
printf("%d", i);
return i;
}
And in my main I have this.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_WIDTH 144
void getFileName(char* array1[MAX_WIDTH]);
int getLineCount(FILE* data, int max);
int main(void)
{
char *array1[MAX_WIDTH];
FILE* data = fopen(*array1, "r");
int max;
getFileName(array1);
getLineCount(data, max);
return 0;
}
My text file is this.
larry snedden 123 mocking bird lane
sponge bob 321 bikini bottom beach
mary fleece 978 pasture road
hairy whodunit 456 get out of here now lane
My issue is that everytime I run this I keep getting a 0 in return and I don't think that's what I'm supposed to be getting back. Also, in my second function I have no idea why I need int max in there but my teacher send I needed it, so if anyone can explain that, that'd be great. I really don't know what I'm doing wrong. I'll appreciate any help I can get.
There were a number of issues with the posted code. I've fixed the problems with the code and left some comments describing what I did. I do think that this code could benefit by some restructuring and renaming (e.g. array1 doesn't tell you what the purpose of the variable is). The getLineCount() function is broken for lines that exceed MAX_WIDTH and ought to be rewritten to count actual lines, not just calls to fgets.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_WIDTH 144
/**
* Gets a handle to the FILE to be processed.
* - Renamed to indicate what the function does
* - removed unnecessary parameter, and added return of FILE*
* - removed the fclose() call
* - added rudimentary error handling.
**/
FILE *getFile()
{
char userIn[MAX_WIDTH+1];
printf("Enter filename: ");
fgets(userIn, MAX_WIDTH, stdin);
userIn[strlen(userIn) - 1] = 0; // chop off newline.
FILE *data = fopen(userIn, "r");
if (data == NULL) {
perror(userIn);
}
return data;
}
/**
* - removed the unnecessary 'max' parameter
* - removed null check of FILE *, since this is now checked elsewhere.
* - adjusted size of array1 for safety.
**/
int getLineCount(FILE* data)
{
int i = 0;
char array1[MAX_WIDTH+1];
while(fgets(array1, MAX_WIDTH, data) != NULL)
{
i+=1;
}
return i;
}
/**
* - removed unnecessary array1 variable
* - removed fopen of uninitialized char array.
* - added some rudimentary error handling.
*/
int main(void)
{
FILE *data = getFile();
if (data != NULL) {
int lc = getLineCount(data);
fclose(data);
printf("%d\n", lc);
return 0;
}
return 1;
}
There are several things I think you should repair at first:
getFileName should help you getting the file name (as the name says), so in that function you shouldn’t have both array1 and userIn (as a matter of fact array1 is not even used in the function, so it can be eliminated all togheter). The paramater and the file name should be ‘the same’.
data is a local FILE pointer, this means once you exit the function you lose it. My recommandation is to make it global, or pass it as an argument from the main class. Also do not close it 1 line after you open it.
I guess the getLineCount is fine, but usually is a good practice to return and printf in main what is returned.
That max that is passed to the second function maybe to help you with the max size of a line? it might be.
Summing up, your getFileName should return the file name, so that userIn is what should be given by that parameter. The File opening should be done IN THE MAIN FUNCTION and be closed after everything you do related to the file, so at the end. Also, open the file after you get the name of the file.
Hopefully it helps you! Keep us tuned with your progress.
I am reading data from a number of files, each containing a list of words. I am trying to display the number of words in each file, but I am running into issues. For example, when I run my code, I receive the output as shown below.
Almost every amount is correctly displayed with the exception of two files, each containing word counts in the thousands. Every other file only has three digits worth of words, and they seem just fine.
I can only guess what this problem could be (not enough space allocated somewhere?) and I do not know how to solve it. I apologize if this is all poorly worded. My brain is fried and I am struggling. Any help would be appreciated.
I've tried to keep my example code as brief as possible. I've cut out a lot of error checking and other tasks related to the full program. I've also added comments where I can. Thanks.
StopWords.c
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <stddef.h>
#include <string.h>
typedef struct
{
char stopwords[2000][60];
int wordcount;
} LangData;
typedef struct
{
int languageCount;
LangData languages[];
} AllData;
main(int argc, char **argv)
{
//Initialize data structures and open path directory
int langCount = 0;
DIR *d;
struct dirent *ep;
d = opendir(argv[1]);
//Count the number of language files in the directory
while(readdir(d))
langCount++;
//Account for "." and ".." in directory
//langCount = langCount - 2 THIS MAKES SENSE RIGHT?
langCount = langCount + 1; //The program crashes if I don't do this, which doesn't make sense to me.
//Allocate space in AllData for languageCount
AllData *data = malloc(sizeof(AllData) + sizeof(LangData)*langCount); //Unsure? Seems to work.
//Reset the directory in preparation for reading data
rewinddir(d);
//Copy all words into respective arrays.
char word[60];
int i = 0;
int k = 0;
int j = 0;
while((ep = readdir(d)) != NULL) //Probably could've used for loops to make this cleaner. Oh well.
{
if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
{
//Filtering "." and ".."
}
else
{
FILE *entry;
//Get string for path (i should make this a function)
char fullpath[100];
strcpy(fullpath, path);
strcat(fullpath, "\\");
strcat(fullpath, ep->d_name);
entry = fopen(fullpath, "r");
//Read all words from file
while(fgets(word, 60, entry) != NULL)
{
j = 0;
//Store each word one character at a time (better way?)
while(word[j] != '\0') //Check for end of word
{
data->languages[i].stopwords[k][j] = word[j];
j++; //Move onto next character
}
k++; //Move onto next word
data->languages[i].wordcount++;
}
//Display number of words in file
printf("%d\n", data->languages[i].wordcount);
i++; Increment index in preparation for next language file.
fclose(entry);
}
}
}
Output
256 //czech.txt: Correct
101 //danish.txt: Correct
101 //dutch.txt: Correct
547 //english.txt: Correct
1835363006 //finnish.txt: Should be 1337. Of course it's 1337.
436 //french.txt: Correct
576 //german.txt: Correct
737 //hungarian.txt: Correct
683853 //icelandic.txt: Should be 1000.
399 //italian.txt: Correct
172 //norwegian.txt: Correct
269 //polish.txt: Correct
437 //portugese.txt: Correct
282 //romanian.txt: Correct
472 //spanish.txt: Correct
386 //swedish.txt: Correct
209 //turkish.txt: Correct
Do the files have more than 2000 words? You have only allocated space for 2000 words so once your program tries to copy over word 2001 it will be doing it outside of the memory allocated for that array, possibly into the space allocated for "wordcount".
Also I want to point out that fgets returns a string to the end of the line or at most n characters (60 in your case), whichever comes first. This will work find if there is only one word per line in the files you are reading from, otherwise will have to locate spaces within the string and count words from there.
If you are simply trying to get a word count, then there is no need to store all the words in an array in the first place. Assuming one word per line, the following should work just as well:
char word[60];
while(fgets(word, 60, entry) != NULL)
{
data->languages[i].wordcount++;
}
fgets reference- http://www.cplusplus.com/reference/cstdio/
Update
I took another look and you might want to try allocating data as follows:
typedef struct
{
char stopwords[2000][60];
int wordcount;
} LangData;
typedef struct
{
int languageCount;
LangData *languages;
} AllData;
AllData *data = malloc(sizeof(AllData));
data->languages = malloc(sizeof(LangData)*langCount);
This way memory is being specifically allocated for the languages array.
I agree that langCount = langCount - 2 makes sense. What error are you getting?
I am writing a C program, which will retrieve the information (header information, pixel information) from a bitmap image, and use that information to create another bitmap image (the new image will obviously be same as the original).
The problem is that, in some cases, extra bytes get added (on their own) to the new image, due to which the image is not formed properly.
In another case, some bytes get missing in the new image, due to which image formation itself fails.
(This happens while writing the pixel information. the bitmap header information gets written properly to the new file.)
I have debugged the code but I couldn't find out what is causing this.
I'll be glad if somebody could tell me what the error is.
//creating a bitmap file
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<math.h>
long extract(FILE *,long ,int );
long extract(FILE *fp1,long offset,int size)
{
unsigned char *ptr;
unsigned char temp='0';
long value=0L;
int i;
//to initialize the ptr
ptr=&temp;
//sets the file pointer at specific position i.e. after the offset
fseek(fp1,offset,SEEK_SET);
//now fgetcing (size) values starting from the offset
for(i=1;i<=size;i++)
{
fread(ptr,sizeof(char),1,fp1);
value=(long)(value+(*ptr)*(pow(256,(i-1)))); //combining the values one after another in a single variable
}
return value;
}
int main()
{
int row,col;
int i,j,k;
int dataoffset,offset;
char magicnum[2];
FILE *fp1,*fp4;
clrscr();
if((fp1=fopen("stripes.bmp","rb"))==NULL)
{
printf("\a\nCant open the image.\nSystem is exiting.");
exit(0);
}
if((fp4=fopen("op.bmp","a"))==NULL)
{
printf("\n\aError while creating a file.\nSystem is exiting ..... ");
exit(0);
}
fputc((int)extract(fp1,0L,1),fp4);
fputc((int)extract(fp1,1L,1),fp4);
fputc((int)extract(fp1,2L,1),fp4);
fputc((int)extract(fp1,3L,1),fp4);
fputc((int)extract(fp1,4L,1),fp4);
fputc((int)extract(fp1,5L,1),fp4);
fputc((int)extract(fp1,6L,1),fp4);
fputc((int)extract(fp1,7L,1),fp4);
fputc((int)extract(fp1,8L,1),fp4);
fputc((int)extract(fp1,9L,1),fp4);
fputc((int)extract(fp1,10L,1),fp4);
fputc((int)extract(fp1,11L,1),fp4);
fputc((int)extract(fp1,12L,1),fp4);
fputc((int)extract(fp1,13L,1),fp4);
fputc((int)extract(fp1,14L,1),fp4);
fputc((int)extract(fp1,15L,1),fp4);
fputc((int)extract(fp1,16L,1),fp4);
fputc((int)extract(fp1,17L,1),fp4);
fputc((int)extract(fp1,18L,1),fp4);
fputc((int)extract(fp1,19L,1),fp4);
fputc((int)extract(fp1,20L,1),fp4);
fputc((int)extract(fp1,21L,1),fp4);
fputc((int)extract(fp1,22L,1),fp4);
fputc((int)extract(fp1,23L,1),fp4);
fputc((int)extract(fp1,24L,1),fp4);
fputc((int)extract(fp1,25L,1),fp4);
fputc((int)extract(fp1,26L,1),fp4);
fputc((int)extract(fp1,27L,1),fp4);
fputc((int)extract(fp1,28L,1),fp4);
fputc((int)extract(fp1,29L,1),fp4);
fputc((int)extract(fp1,30L,1),fp4);
fputc((int)extract(fp1,31L,1),fp4);
fputc((int)extract(fp1,32L,1),fp4);
fputc((int)extract(fp1,33L,1),fp4);
fputc((int)extract(fp1,34L,1),fp4);
fputc((int)extract(fp1,35L,1),fp4);
fputc((int)extract(fp1,36L,1),fp4);
fputc((int)extract(fp1,37L,1),fp4);
fputc((int)extract(fp1,38L,1),fp4);
fputc((int)extract(fp1,39L,1),fp4);
fputc((int)extract(fp1,40L,1),fp4);
fputc((int)extract(fp1,41L,1),fp4);
fputc((int)extract(fp1,42L,1),fp4);
fputc((int)extract(fp1,43L,1),fp4);
fputc((int)extract(fp1,44L,1),fp4);
fputc((int)extract(fp1,45L,1),fp4);
fputc((int)extract(fp1,46L,1),fp4);
fputc((int)extract(fp1,47L,1),fp4);
fputc((int)extract(fp1,48L,1),fp4);
fputc((int)extract(fp1,49L,1),fp4);
fputc((int)extract(fp1,50L,1),fp4);
fputc((int)extract(fp1,51L,1),fp4);
fputc((int)extract(fp1,52L,1),fp4);
fputc((int)extract(fp1,53L,1),fp4);
//setting the file pointer at the beginning
rewind(fp1);
/*CHECKING WHETHER THE FILE IS IN BMP FORMAT OR NOT, WE CHECK THE MAGIC NUMBER OF THE FILE, MAGIC NUMBER'S OFFSET IS 0 i.e. IT'S STORED AT THE FRONT OF THE IMAGE, AND THE SIZE IS 2*/
//at first extracting the magic number
for(i=0;i<2;i++)
{
magicnum[i]=(char)extract(fp1,i,1);
}
//now checking
if((magicnum[0]=='B') && (magicnum[1]=='M'))
;
else
{
printf("\aThe image is not a bitmap image.\nSystem is exiting ... ");
exit(0);
}
//storing the header information
//get the starting position or offset of the data(pixel)
dataoffset=(int)extract(fp1,10,4);
//get the number of rows
row=(int)extract(fp1,22,4);
//get the number of columns
col=(int)extract(fp1,18,4);
//storing the data
offset=dataoffset;
for(j=0;j<col;j++)
{
for(k=0;k<row;k++)
{
for(i=0;i<=2;i++)
{
fputc((int)extract(fp1,offset++,1),fp4);
}
}
}
fcloseall();
return 0;
}
Make sure you open the output file in binary mode as well.
If you don't do that, the byte value corresponding to '\n' may be expanded to carriage return and line feed.
Consider this line:
value=(long)(value+(*ptr)*(pow(256,(i-1))));
pow is a floating point function returning a double. This means that (*ptr) is implicitly casted to double. The whole expression (value+(*ptr)*(pow(256,(i-1)))) will be a double. Now this can be larger than 2147483647 which is the largest number a long can hold (on most common 32-bit platforms), and the result when converting an out of range double to long is undefined. See what happens on this example:
#include <stdio.h>
int main(int argc, char **argv) {
int i;
for (i = 0; i < 10; i++) {
double d = 2147483647.0d + i;
printf("double=%f long=%ld\n", d, (long)d);
}
return 0;
}
Here is the output when I run it on my system: (hidden in case you want to guess or test it yourself first):
double=2147483647.000000 long=2147483647
double=2147483648.000000 long=-2147483648
double=2147483649.000000 long=-2147483648
double=2147483650.000000 long=-2147483648
double=2147483651.000000 long=-2147483648
double=2147483652.000000 long=-2147483648
double=2147483653.000000 long=-2147483648
double=2147483654.000000 long=-2147483648
double=2147483655.000000 long=-2147483648
double=2147483656.000000 long=-2147483648
One way to fix it would be to change it to unsigned long instead.
Personally I'd use 1 << (8*(i-1)) instead of pow to avoid messing with floating point, but there is lots of other things that I'd do very different too, but that is probably out of scope for this question (might be a question for the code review site).