Storing strings in array in C - c

I have read a lot of questions on this, and using them I have altered my code and have created code which I thought would work.
I think it's my understanding of C, which is failing me here as I can't see where I'm going wrong.
I get no compilation errors, but when I run i receive 'FileReader.exe has stopped working' from the command prompt.
My code is :
void storeFile(){
int i = 0;
char allWords [45440][25];
FILE *fp = fopen("fileToOpen.txt", "r");
while (i <= 45440){
char buffer[25];
fgets(buffer, 25, fp);
printf("The word read into buffer is : %s",buffer);
strcpy(allWords[i], buffer);
printf("The word in allWords[%d] is : %s", i, allWords[i]);
//allWords[i][strlen(allWords[i])-1] = '\0';
i = i + 1;
}
fclose(fp);
}
There are 45440 lines in the file, and no words longer than 25 char's in length. I'm trying to read each word into a char array named buffer, then store that buffer in an array of char arrays named allWords.
I am trying to get this part working, before I refactor to return the array to the main method (which I feel won't be a fun experience).

You are trying to allocate more than a megabyte (45440*25) worth of data in automatic storage. On many architectures this results in stack overflow before your file-reading code even gets to run.
You can work around this problem by allocating allWords statically, like this
static char allWords [45440][25];
or dynamically, like this:
char (*allWords)[25] = malloc(45440 * sizeof(*allWords));
Note that using buffer in the call to fgets is not required, because allWords[i] can be used instead, without strcpy:
fgets(allWords[i], sizeof(*allWords)-1, fp);
Also note that an assumption about file size is unnecessary: you can continue calling fgets until it returns NULL; this indicates that the end of the file has been reached, so you can exit the loop using break.

Related

Having issues with array holding its value

I am kind of new when it comes to C. Took a class on it in college but I just don't practice it much. Well my issue that I'm having is that I'm trying to take an text file and convert it into an array. I have been able to get the text file and print it into the console but when I save run the while statement to read each line, my whole array gets overwritten. For instance if my last line on my text file is 19, my array[0] gets over written to what should be on array[18].
I know the indentations are off a off, coding is a mess, and forgive me on the printf commands, I'm only using them to troubleshoot my code. The text file will have IP address on each line.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#define MAX_LINE_LENGTH 16
int main()
{
int lineCntPOSlist = 0;
int lineCnt = 0;
int i = 0;
FILE *textfile;
char line[MAX_LINE_LENGTH];
char* posList[50];
textfile = fopen("pos-list.txt", "r");
if(textfile == NULL)
{
int posListExist = 0;
system("cls");
printf("File Exist %d\n", posListExist);
fprintf(stderr, "**File open failed\n Make sure there is a pos-list.txt file");
return 1;
}
system("cls");
while(fgets(line, MAX_LINE_LENGTH, textfile))
{
printf("Line %d: %s",lineCnt , line);
posList[lineCnt] = line;
printf("posList[%d] = %s\n", lineCnt, posList[lineCnt] );
printf("posList[0] = %s\n", posList[0] );
lineCnt = ++lineCnt;
lineCntPOSlist = ++lineCntPOSlist;
}
fclose(textfile);
return 0;
}
This:
posList[lineCnt] = line;
simply sets posList[lineCnt] to point at the line buffer in line, it copies zero characters of actual data. In higher-level languages where strings have a bit more presence, this would make sense, but in C it doesn't.
Since there is only one line buffer, it will always hold the characters making up the most recently loaded line, and thus it will act as if previous lines are being "overwritten".
There are several solutions, here are a few:
Make posList into a proper array of strings, but that requires you to decide max length in advance and will waste the space for shorter lines.
Use something like strdup() to allocate copies on the heap of each line, and store pointers to those.
Use a more "proper" reallocating array for the storage and store line pointers (or offsets, which might be better suited due to the reallocating) in the array for easier access.

Using Fgets in two ways

I looked through some "FGETS" questions before posting, and what i gathered is it may be a new line character thats causing the issue for the manual input.
int main ( int argc, char *argv[] ){
char temp[1000];
FILE *user_file;
printf("Starting....\n"); //Used for user visual.
if(argc == 2){ //open file
user_file = fopen(argv[1],"r");
if( user_file == NULL ){
printf("No file was found.");
exit(2);
}else{
fgets(temp,strlen(temp),user_file);
}
}else if( argc > 2 ){ // Will exit if arguments are greater than 2.
printf("Maximum args 2.\n");
exit(1);
}else{
printf("File was not provided, please enter the text to convert.\n"); //If the user doesnt provide a file allow manual input.
fgets(temp,strlen(temp),stdin);
}
printf("%s\n",temp);
return 0;
}//End main
Questions:
Why is fgets not opening the txt file I provide it with on the cmd line, and storing it to the temp array?
Why is Fgets being skipped over in the "else" statment if the file is not provided?
Why is print being skipped over in both instances?
Hey and by the way thank you very much for the assistance.
If you know a similar question that has been asked, can you post it in the comments so I can read it.
Your code has multiple problems.
Here's the first problem:
char temp[1000];
Your buffer declaration does not initialize the buffer's contents - so the value of each char value will be whatever was in the raw memory previously. In C most strings are "null-terminated" so having a terminating NULL (0 - zero) is important otherwise you can run into buffer-overruns.
The "best" approach is to zero-out (zero-initialize) the array/buffer before you use it, like so (in C99):
char temp[1000] = {0};
...this way temp will contain all 0 values (NULL) so anything written to it (provided it's no longer than 999 bytes) will automatically have a null-terminator (though fgets will append a terminating 0 value, but not every function in C does this).
The second problem is related to the first: you're using the runtime string-length function strlen to get the size of the strlen buffer. This is incorrect as the buffer sized is fixed at compile-time to 1000. The strlen will return the index of the first 0 (NULL) char value, which is undefined behavior at this point because you haven't zero-initialized the buffer anyway (so it could return 0 immediately if the buffer's original raw data contained a zero, or it could overrun 1000 because there was never any zero value.
...thus you need to re-use the buffer-length, like so:
#define TEMP_LENGTH 1000
char temp[ TEMP_LENGTH ];
...
fgets( temp, TEMP_LENGTH, user_file );
Finally, you're making the same mistake when you call fgets( temp, ..., stdin ).
The array temp[] is uninitialized, and you attempt to find strlen(temp). You don't even know if there is a NUL stored in the array. Try doing:
#define MAXLINE 1000
and changing your calls to fgets():
fgets(temp, MAXLINE, user_file);
...
fgets(temp, MAXLINE, stdin);
Here problem is in your code, instead of passed numerical value in second argument you passed strlen(temp).
fgets(temp,strlen(temp),user_file);
right way is :-
fgets(temp,1000,user_file);

New to C, trying to better understand char arrays, pointers, reading in files, etc

Alright, so I am working on linux and emacs for the first time using C, and coming from pretty beginner level java programming in eclipse, my new CS course is really daunting. SO much stuff has been thrown at me as if I already knew it...
Anyway, the current part of my assignment I am working on involves reading in text from a file (doing that by piping a text file as standard input into my program). Currently I had three functions, a main function where I read in the file / call other functions, a function that reverses the order of a single word (apple becomes elppa) with *char beg and *char end as parameters, and a function that reverses the order of every word in a line of words, calling the previous function and taking a char *str as a parameter.
I am having trouble reading in the files in my main method in a way that makes it easy to utilize these functions. Here's a snippet of how I am reading them in currently, but as you can see I haven't figured out a way to store a line of words and send that into my function (I need to reverse line by line, so I can't just add every single char to one long array)
enter code here``
char line[8192]
int location = 0;
FILE *in = stdin;
int buff = 0;
while (buff = fgetc(in))
{
fprintf(stderr, "Character is: %d '%c' \n", buff, (char)buff);
if (buff == EOF)
{
break;
}
line[location] = (char)buff;
location++;
}
line[location] = '\0';
If you want to get a whole line, you can do this:
char line[MAX_LINE_SIZE];
fscanf(in, "%[^\n]", line);
//do whatever you need with the line
fscanf(in, "%[\n]", line);
The first fscanf call reads a whole line and store in variable line.
But it doesn't skip that line! If you use it again, it will store the very same line.
The second fscanf call is for this: it stores '\n' in variable line and skips the line you read previously.
If you want, you can create another buffer to get the '\n' and skip the line:
char garbage[2];
fscanf(in, "%[\n]", garbage);
I hope this helps.

Program.exe has stopped working error: fgets function

My program written in C below is running to a certain point. However, it stops in the middle of, what I would deem, error-less code. Coming from Java, I'm a newbie with C so any help would be much appreciated.
#include <stdio.h>
#include <stdlib.h>
void getInput(char *input, const char *rs[]){// Args are the user input and our reserved words array.
printf(">>"); fgets(input, 1000, stdin);// Getting our normal command
int i;
for(i = 0; i < (int)sizeof(rs); i++){
if(strcmp(input, rs[i]) != 0){
printf("You said: %s", input); //PROGRAM BREAKS AFTER THIS LINE
}
}
printf("Size of \"input\" is: %d\n", sizeof(input));// Just checking the size of input
free(input);// Deallocating input since we won't need it anymore.
}
int main(){
char *input = malloc(500 * sizeof(char));// Command line input
const char *rs[1];// Reserved words array.
rs[0] = "print";
getInput(input, rs);
getch();
}
A couple of problems, mostly stemming from treating C as if it had strings and arrays like Java. It doesn't, it just has blocks of bytes and some functions to do string-like and array-like things with them.
So firstly, malloc(500 * sizeof(char)) allocates 500 bytes (sizeof char is 1 by definition). Later you fgets(input, 1000...) on those 500 bytes. Not good.
char *rs[1] allocates an array of 1 character pointer. It does not allocate any memory for any strings. rs[0] = "print" is OK because "print" allocates 6 bytes and the assignment makes rs[0] point to them. But then you pass rs to the function getInput and call sizeof on it, which gives you the size of a single pointer (probably 4 or 8 bytes) because C doesn't keep array dimensions either--It just passes a pointer to the start of the array. You need to pass the length yourself.
You aren't checking the return value of fgets(). And even if you weren't reading 1000 bytes into a 500-byte buffer and fgets were working perfectly, your strcmp() will always fail because fgets() includes the newline in the string.
Finally, sizeof(input) is another size-of-pointer, not an array dimension. you probably mean strlen(input)?

Reading strings and integers from one binary text in C

I'm using C and I want to read from a binaryFile.
I know that it is contain strings in the following way: Length of a string, the string itself, the length of a string, string itself, and so on...
I want to count the number of times which the string Str appears in the binary file.
So I want to do something like this:
int N;
while (!feof(file)){
if (fread(&N, sizeof(int), 1, file)==1)
...
Now I need to get the string itself. I know it's length. Should I do a 'for'
loop and get with fgetc char by char? I know I'm not allowed to use fscanf since
it's not a text file, but can I use fgetc? And would I get what I'm expecting for
my string? (To use dynamic allocation for char* for it with the size of the length
and use strcpy to add it to the current string?)
You could allocate some memory with malloc then fread into that buffer:
char *str;
/* ... */
if (fread(&N, sizeof(int), 1, file)==1)
{
/* check that N > 0 */
str = malloc(N+1);
if (fread(str, sizeof(char), N, file) == N)
{
str[N] = '\0'; /* terminate str */
printf("Read %d chars: %s\n", N, str);
}
free(str);
}
You should probably loop on:
while (fread(&N, sizeof(int), 1, file) == 1)
{
// Check N for sanity
char *buffer = malloc(N+1);
// Check malloc succeeded
if (fread(buffer, N, 1, file) != 1)
...process error...
buffer[N] = '\0'; // Null terminate for sanity's sake
...store buffer (the pointer) for later processing so you aren't leaking...
...or free it if you won't need it later...
}
You could use getc() or fgetc() in a loop; that would work. However, the direct fread() is much simpler (and is coded as if it uses getc() in a loop).
You might want to do some sanity checking on N before blindly using it with malloc(). In particular, negative values are likely to lead to much unhappiness.
The file format as written is tied to one class of machine — either big-endian or little-endian, and with the fixed size of int (probably 32-bits). Writing more portable data is slightly fiddlier, but eminently doable — but probably not relevant to you just yet.
Using feof() is seldom the correct way to test for whether to continue with a loop. Indeed, there is not often a need to use feof() in code. When it is used, it is because an I/O operation 'failed' and you need to disambiguate between 'it was not an error — just EOF' and 'there was some sort of error on the device'.

Resources