2

I'm having some trouble getting text into a char array. It worked fine when I set a static size for the array like

char speech[15000];

but that was inefficient so I tried using calloc instead. That made it stop working. The array exists at the right size, but nothing gets written in. Here's the relevant code. What am I doing wrong?

int main() {

FILE* inFile;
int i;
int count = 0;

printf("\nOpening file April_30_1789.txt\n");

inFile = fopen("./speeches/April_30_1789.txt", "r");

if(inFile == NULL) {
    printf("Could not find April_30_1789.txt\n");
    return -1;
}

char ch;

while((ch = fgetc(inFile) != EOF)) count++;

rewind(inFile);

int size = count;

printf("Size of the array is %d\n", size);

char *speech = (char *)malloc(size*sizeof(char) + 1*sizeof(char));

fscanf(inFile, "%s", speech);

printf("Closing the file.\n");
fclose(inFile);

printf("%s", speech);

printf("\n\nDone\n");

return 0;

}

Currently, this gives me

Opening file April_30_1789.txt
Size of the array is 8617
Closing the file.
Fellow-Citizens

Done
Gary M
  • 167
  • 2
  • 2
  • 9

3 Answers3

10

Possible duplicate of Reading the whole text file into a char array in C.


Your problem : fscanf with the "%s" format will read up to the first whitespace encountered.

Possible solution (error-checking is omitted for conciseness) :

#include <stdio.h>  /* printf */
#include <stdlib.h> /* fopen, fseek, ... */

char *buffer = NULL;
size_t size = 0;

/* Open your_file in read-only mode */
FILE *fp = fopen("your_file_name", "r");

/* Get the buffer size */
fseek(fp, 0, SEEK_END); /* Go to end of file */
size = ftell(fp); /* How many bytes did we pass ? */

/* Set position of stream to the beginning */
rewind(fp);

/* Allocate the buffer (no need to initialize it with calloc) */
buffer = malloc((size + 1) * sizeof(*buffer)); /* size + 1 byte for the \0 */

/* Read the file into the buffer */
fread(buffer, size, 1, fp); /* Read 1 chunk of size bytes from fp into buffer */

/* NULL-terminate the buffer */
buffer[size] = '\0';

/* Print it ! */
printf("%s\n", buffer);
Community
  • 1
  • 1
Chnossos
  • 9,971
  • 4
  • 28
  • 40
  • Well, this worked out really well. It looks cleaner than what I had before (never used fseek/fread before) and I may just stick with this. For future reference though, what was my original code doing wrong? – Gary M Mar 27 '14 at 20:02
  • `fscanf` with the `"%s"` format will read up to the first whitespace encountered. For instance if I use your code to print my main.c file, only `#include` is actually printed. – Chnossos Mar 27 '14 at 20:10
  • Ah, that explains it. So if I had wanted to use my original code, I would just have to have it keep reading till EOF then, right? – Gary M Mar 27 '14 at 20:22
  • You could use a loop, but since whitespaces are discarded, you would end up loosing your document's formatting. Using `fread` will keep the formatting. Oh and by the way, this line `while((ch = fgetc(inFile) != EOF)) count++;` should be rewritten as `while((ch = fgetc(inFile)) != EOF) count++;`. – Chnossos Mar 27 '14 at 20:28
1

as pmg said while((ch = fgetc(inFile) != EOF)) count++; makes your file pointer point at the end, use rewind(FILE* fileptr); to return to beginning of file.

nikola-miljkovic
  • 652
  • 4
  • 14
  • This seems to work, but it only worked for the first word of the text, which was "Fellow-Citizens". Would that be a problem in reading the text into the array or is it an error with printing the array? – Gary M Mar 27 '14 at 19:44
  • @user2797058 Change `fscanf(inFile, "%s", &speech);` to `fscanf(inFile, "%s", speech);` – Filipe Gonçalves Mar 27 '14 at 19:47
  • @FilipeGonçalves Whoops, forgot to mention that I already did. I'll update the OP. It still only prints out Fellow-Citizens – Gary M Mar 27 '14 at 19:49
  • @nikolaMM94 It seems like the array is the correct size. Microsoft Word gave about the same number of characters that the variable count is reporting. If I did malloc right, it should be the right size – Gary M Mar 27 '14 at 19:54
  • @nikolaMM94 Would this work? char *speech = (char *)malloc(size*sizeof(char) + 1*sizeof(char)); This is what I have right now and it still gives only Fellow-Citizens – Gary M Mar 27 '14 at 19:57
  • Yes, no need 1*sizeof, sizeof and if that doesn't work try reading into buffer. – nikola-miljkovic Mar 27 '14 at 19:57
1

Your file pointer inFile is pointing to end

I'd do something like following :

long lSize;

fseek( inFile , 0L , SEEK_END); //use the function instead
lSize = ftell( inFile );       // to know the file size
rewind( inFile );             // Now point to beginning 

char* speech = calloc( 1, lSize+1 );
if( speech )
{
    if( fread( speech , lSize, 1 , inFile) != 1)
    {
      fclose(inFile) ;
      free(speech); 
      exit(1);
    }
}

// Process the speech Here


fclose(inFile); 
free(speech); // Don't forget to free the allocated memory !
P0W
  • 46,614
  • 9
  • 72
  • 119