I'am using fgets to get inputs.
Input:
station
cricket
expected output:
station
cricket
char str[size_limit];
scanf("%d", &n);
for(i=0; i<n; i++){
fgets(str, sizeof str, stdin);
}
printf("%s", ??);
It's not clear what "compute the outputs" means, but if you want to read all the lines of text in a file and then compute a result from those lines of text, something like this will work (in this case I just print out the lines of text from the in-memory array, but you can modify it as necessary):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char ** linesBuf = NULL;
size_t numSlotsInArray = 0;
int numLinesRead = 0;
char buf[512];
while(fgets(buf, sizeof(buf), stdin))
{
if (numLinesRead >= numSlotsInArray)
{
// Whoops, our allocated array is too short, make it larger
numSlotsInArray = (numSlotsInArray == 0) ? 100 : (numSlotsInArray*2);
linesBuf = realloc(linesBuf, numSlotsInArray*sizeof(char*));
if (linesBuf == NULL)
{
perror("realloc");
exit(10);
}
}
char * nextLine = strdup(buf);
if (nextLine == NULL)
{
perror("strdup");
exit(10);
}
linesBuf[numLinesRead++] = nextLine;
}
printf("total number of lines read: %i\n", numLinesRead);
for(size_t i=0; i<numLinesRead; i++)
{
printf("Line %zu is: [%s]\n", i, linesBuf[i]);
}
// Clean up to avoid leaking memory
for(size_t i=0; i<numLinesRead; i++) free(linesBuf[i]);
free(linesBuf);
return 0;
}
You can run this with stdin redirected from a file (e.g. ./a.out < input_file.txt) or if you run it from a Terminal window, press Ctrl-D to indicate end-of-file to the program.
Related
Hi I was trying to create an array of string of an undetermined length in c.
This is my code :
int main()
{
int lineCount=linesCount();
char text[lineCount][10];
printf("%d",lineCount);
FILE * fpointer = fopen("test.txt","r");
fgets(text,10,fpointer);
fclose(fpointer);
printf("%s",text);
return 0;
}
I would like to replace 10 in
char text[lineCount][10];
My code reads out a file I already made the amount of lines dynamic.
Since the line length is unpredictable I would like to replace 10 by a something dynamic.
Thanks in advance.
To do this cleanly, we want a char * array rather than an 2D char array:
char *text[lineCount];
And, we need to use memory from the heap to store the individual lines.
Also, don't "hardwire" so called "magic" numbers like 10. Use an enum or #define (e.g) #define MAXWID 10. Note that with the solution below, we obviate the need for using the magic number at all.
Also, note the use of sizeof(buf) below instead of a magic number.
And, we want [separate] loops when reading and printing.
Anyway, here's the refactored code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
linesCount(void)
{
return 23;
}
int
main(void)
{
int lineCount = linesCount();
char *text[lineCount];
char buf[10000];
printf("%d", lineCount);
// open file and _check_ the return
const char *file = "test.txt";
FILE *fpointer = fopen(file, "r");
if (fpointer == NULL) {
perror(file);
exit(1);
}
int i = 0;
while (fgets(buf, sizeof(buf), fpointer) != NULL) {
// strip newline
buf[strcspn(buf,"\n")] = 0;
// store line -- we must allocate this
text[i++] = strdup(buf);
}
fclose(fpointer);
for (i = 0; i < lineCount; ++i)
printf("%s\n", text[i]);
return 0;
}
UPDATE:
The above code is derived from your original code. But, it assumes that the linesCount function can predict the number of lines. And, it doesn't check against overflow of the fixed length text array.
Here is a more generalized version that will allow an arbitrary number of lines with varying line lengths:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(void)
{
int lineCount = 0;
char **text = NULL;
char buf[10000];
// open file and _check_ the return
const char *file = "test.txt";
FILE *fpointer = fopen(file, "r");
if (fpointer == NULL) {
perror(file);
exit(1);
}
int i = 0;
while (fgets(buf, sizeof(buf), fpointer) != NULL) {
// strip newline
buf[strcspn(buf,"\n")] = 0;
++lineCount;
// increase number of lines in array
text = realloc(text,sizeof(*text) * lineCount);
if (text == NULL) {
perror("realloc");
exit(1);
}
// store line -- we must allocate this
text[lineCount - 1] = strdup(buf);
}
fclose(fpointer);
// print the lines
for (i = 0; i < lineCount; ++i)
printf("%s\n", text[i]);
// more processing ...
// free the lines
for (i = 0; i < lineCount; ++i)
free(text[i]);
// free the list of lines
free(text);
return 0;
}
In file I need to read some inputs:
this is an example:
8 15
[1,1] v=5 s=4#o
[4,2] v=1 s=9#x
typedef struct{
int red2;
int stupac2;
int visina;
int sirina;
char boja[10];
}Tunel;
FILE* fin = fopen("farbanje.txt", "r");
Tunel* tuneli = malloc(sizeof(Tunel)*50);
// if(fin!=0)
fscanf(fin,"%d %d", &r,&s);
printf("%d %d", r,s);
int p=0;
while (fscanf(fin, "[%d,%d]", &tuneli[p].red2, &tuneli[p].stupac2) == 2)
{
p++;
}
for(i=0;i<p;i++)
{
printf("[%d,%d]", tuneli[i].red2, tuneli[i].stupac2);
}
Problem is that it wont read me properly inputs from here: [1,1] v=5 s=4#o
Last line where i use printf shows some random numbers.
Agree it is better to use fgets
But if you want to continue to use your current approach,
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int red2;
int stupac2;
int visina;
int sirina;
char boja[10];
}Tunel;
int main(){
int r, s, i;
FILE*fin=fopen("farbanje.txt", "r");
if(fin==NULL) {
printf("error reading file\n");
return 1;
}
Tunel *tuneli=(Tunel*)malloc(sizeof(Tunel)*50);
fscanf(fin,"%d %d\n", &r,&s);
printf("%d %d", r,s);
int p=0;
while (fscanf(fin, " [%d,%d]%*[^\n]", &tuneli[p].red2, &tuneli[p].stupac2) == 2)
{
p++;
}
fclose(fin);
for(i=0;i<p;i++)
{
printf("[%d,%d]", tuneli[i].red2, tuneli[i].stupac2);
}
}
Last line where i use printf shows some random numbers....
The random numbers you see are because the buffers to print were not properly populated yet.
This example shows how to read the file, using fgets() to read a line buffer, then use sscanf() to parse the first two values from the lines. (read in-code comments for a few other tips.)
int main(void)//minimum signature for main includes 'void'
{
int r = 0;
int s = 0;
char line[80] = {0};//{initializer for arrays}
int p = 0;
Tunel *tuneli = malloc(sizeof(*tuneli)*50);
if(tuneli)//always test return of malloc before using it
{
FILE *fin = fopen(".\\farbanje.txt", "r");
if(fin)//always test return of fopen before using it
{
fgets(line, sizeof(line), fin);
sscanf(line, "%d %d", &r, &s);
while(fgets(line, sizeof(line), fin))
{
sscanf(line, " [%d,%d]", &tuneli[p].red2, &tuneli[p].stupac2);
//note space ^ here to read only visible characters
printf("[%d,%d]\n", tuneli[p].red2, tuneli[p].stupac2);//content is now populated corretly
p++;
}
fclose(fin);//close when finished
}
free(tuneli);//free when done to prevent memory leaks
}
return 0;
}
When I want to try to store some lines in the array from the text file it only prints the last line of the text file many times.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
FILE *fp;
char str[1000];
char a[3][1000];
fp = fopen("filename.txt", "r");
if (fp == NULL) {
printf("Could not open file ");
return 1;
}
while (fgets(str, 1000, fp) != 0) {
printf("%s", str);
}
for (int i = 0; i <= 3; i++) {
strcpy(a[i], str);
printf("\n%s\n", a[i]);
}
fclose(fp);
return 0;
}
my text file
stan nu'est
nu'est stan
nu'est ot5
minhyun is a nu'est member
It only prints minhyun is a nu'est member 3 times.
Can someone please help me?
while (fgets(str, 1000, fp) != 0) {
printf("%s", str); //
}
stan nu'est
nu'est stan
nu'est ot5
and then after the end of while loop the str will store only the last line, which is
minhyun is a nu'est member
int the below written for loop, minhyun is a nu'est member will be copied to the a[i] for 4 times and printed.
for(int i = 0; i <= 3; i++){
strcpy(a[i], str);
printf("\n%s\n", a[i]);
}
to Copy the entire text to the array str, you may use below given code,
char kr;
int i=0;
do{
kr=fgetc(fp);
str[i++]=kr;
}while(kr!=EOF);
str[i]='\0';
and, to read the first three line of the text into the str array in order, you can use below given code.
int j=0,k;
for(i=0;i<3;i++,j++)
{
for(k=0;str[j]!='\n'&&str[j]!='\0';j++,k++)
a[i][k]=str[j];
a[i][k]='\0';
printf("\n%s\n", a[i]);
}
Here is the entire code below,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *fp;
char str[1000];
char a[3][1000];
fp=fopen("filename.txt","r");
if(fp == NULL)
{
printf("Could not open file ");
return 1;
}
char kr;
int i=0;
do{
kr=fgetc(fp);
str[i++]=kr;
}while(kr!=EOF);
str[i]='\0';
int j=0,k;
for(i=0;i<3;i++,j++)
{
for(k=0;str[j]!='\n'&&str[j]!='\0';j++,k++)
a[i][k]=str[j];
a[i][k]='\0';
printf("\n%s\n", a[i]);
}
fclose(fp);
return 0;
}
So this is my second time adapting my code to fscanf to get what I want. I threw some comments next to the output. The main issue I am having is that the one null character or space is getting added into the array. I have tried to check for the null char and the space in the string variable and it does not catch it. I am a little stuck and would like to know why my code is letting that one null character through?
Part where it is slipping up "Pardon, O King," output:King -- 1; -- 1
so here it parses king a word and then ," goes through the strip function and becomes \0, then my check later down the road allows it through??
Input: a short story containing apostrophes and commas (the lion's rock. First, the lion woke up)
//Output: Every unique word that shows up with how many times it shows up.
//Lion -- 1
//s - 12
//lion -- 8
//tree -- 2
//-- 1 //this is the line that prints a null char?
//cub -- //3 it is not a space! I even check if it is \0 before entering
//it into the array. Any ideas (this is my 2nd time)?
//trying to rewrite my code around a fscanf function.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
//Remove non-alpha numeric characters
void strip_word(char* string)
{
char* string_two = calloc(80, sizeof(char));
int i;
int c = 0;
for(i = 0; i < strlen(string); i++)
{
if(isalnum(string[i]))
{
string_two[c] = string[i];
++c;
}
}
string_two[i] = '\0';
strcpy(string, string_two);
free(string_two);
}
//Parse through file
void file_parse(FILE* text_file, char*** word_array, int** count_array, int* total_count, int* unique_count)
{
int mem_Size = 8;
int is_unique = 1;
char** words = calloc(mem_Size, sizeof(char *)); //Dynamically allocate array of size 8 of char*
if (words == NULL)
{
fprintf(stderr, "ERROR: calloc() failed!");
}
int* counts = calloc(mem_Size, sizeof(int)); //Dynamically allocate array of size 8 of int
if (counts == NULL)
{
fprintf(stderr, "ERROR: calloc() failed!");
}
printf("Allocated initial parallel arrays of size 8.\n");
fflush(stdout);
char* string;
while('A')
{
is_unique = 1;
fscanf(text_file, " ,");
fscanf(text_file, " '");
while(fscanf(text_file, "%m[^,' \n]", &string) == 1) //%m length modifier
{
is_unique = 1;
strip_word(string);
if(string == '\0') continue; //if the string is empty move to next iteration
else
{
int i = 0;
++(*total_count);
for(i = 0; i < (*unique_count); i++)
{
if(strcmp(string, words[i]) == 0)
{
counts[i]++;
is_unique = 0;
break;
}
}
if(is_unique)
{
++(*unique_count);
if((*unique_count) >= mem_Size)
{
mem_Size = mem_Size*2;
words = realloc(words, mem_Size * sizeof(char *));
counts = realloc(counts, mem_Size * sizeof(int));
if(words == NULL || counts == NULL)
{
fprintf(stderr, "ERROR: realloc() failed!");
}
printf("Re-allocated parallel arrays to be size %d.\n", mem_Size);
fflush(stdout);
}
words[(*unique_count)-1] = calloc(strlen(string) + 1, sizeof(char));
strcpy(words[(*unique_count)-1], string);
counts[(*unique_count) - 1] = 1;
}
}
free(string);
}
if(feof(text_file)) break;
}
printf("All done (successfully read %d words; %d unique words).\n", *total_count, *unique_count);
fflush(stdout);
*word_array = words;
*count_array = counts;
}
int main(int argc, char* argv[])
{
if(argc < 2 || argc > 3) //Checks if too little or too many args
{
fprintf(stderr, "ERROR: Invalid Arguements\n");
return EXIT_FAILURE;
}
FILE * text_file = fopen(argv[1], "r");
if (text_file == NULL)
{
fprintf(stderr, "ERROR: Can't open file");
}
int total_count = 0;
int unique_count = 0;
char** word_array;
int* count_array;
file_parse(text_file, &word_array, &count_array, &total_count, &unique_count);
fclose(text_file);
int i;
if(argv[2] == NULL)
{
printf("All words (and corresponding counts) are:\n");
fflush(stdout);
for(i = 0; i < unique_count; i++)
{
printf("%s -- %d\n", word_array[i], count_array[i]);
fflush(stdout);
}
}
else
{
printf("First %d words (and corresponding counts) are:\n", atoi(argv[2]));
fflush(stdout);
for(i = 0; i < atoi(argv[2]); i++)
{
printf("%s -- %d\n", word_array[i], count_array[i]);
fflush(stdout);
}
}
for(i = 0; i < unique_count; i++)
{
free(word_array[i]);
}
free(word_array);
free(count_array);
return EXIT_SUCCESS;
}
I'm not sure quite what's going wrong with your code. I'm working on macOS Sierra 10.12.3 with GCC 6.3.0, and the local fscanf() does not support the m modifier. Consequently, I modified the code to use a fixed size string of 80 bytes. When I do that (and only that), your program runs without obvious problem (certainly on the input "the lion's rock. First, the lion woke up").
I also think that the while ('A') loop (which should be written conventionally while (1) if it is used at all) is undesirable. I wrote a function read_word() which gets the next 'word', including skipping blanks, commas and quotes, and use that to control the loop. I left your memory allocation in file_parse() unchanged. I did get rid of the memory allocation in strip_word() (eventually — it worked OK as written too).
That left me with:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
static void strip_word(char *string)
{
char string_two[80];
int i;
int c = 0;
int len = strlen(string);
for (i = 0; i < len; i++)
{
if (isalnum(string[i]))
string_two[c++] = string[i];
}
string_two[c] = '\0';
strcpy(string, string_two);
}
static int read_word(FILE *fp, char *string)
{
if (fscanf(fp, " ,") == EOF ||
fscanf(fp, " '") == EOF ||
fscanf(fp, "%79[^,' \n]", string) != 1)
return EOF;
return 0;
}
static void file_parse(FILE *text_file, char ***word_array, int **count_array, int *total_count, int *unique_count)
{
int mem_Size = 8;
char **words = calloc(mem_Size, sizeof(char *));
if (words == NULL)
{
fprintf(stderr, "ERROR: calloc() failed!");
}
int *counts = calloc(mem_Size, sizeof(int));
if (counts == NULL)
{
fprintf(stderr, "ERROR: calloc() failed!");
}
printf("Allocated initial parallel arrays of size 8.\n");
fflush(stdout);
char string[80];
while (read_word(text_file, string) != EOF)
{
int is_unique = 1;
printf("Got [%s]\n", string);
strip_word(string);
if (string[0] == '\0')
continue;
else
{
int i = 0;
++(*total_count);
for (i = 0; i < (*unique_count); i++)
{
if (strcmp(string, words[i]) == 0)
{
counts[i]++;
is_unique = 0;
break;
}
}
if (is_unique)
{
++(*unique_count);
if ((*unique_count) >= mem_Size)
{
mem_Size = mem_Size * 2;
words = realloc(words, mem_Size * sizeof(char *));
counts = realloc(counts, mem_Size * sizeof(int));
if (words == NULL || counts == NULL)
{
fprintf(stderr, "ERROR: realloc() failed!");
exit(EXIT_FAILURE);
}
printf("Re-allocated parallel arrays to be size %d.\n", mem_Size);
fflush(stdout);
}
words[(*unique_count) - 1] = calloc(strlen(string) + 1, sizeof(char));
strcpy(words[(*unique_count) - 1], string);
counts[(*unique_count) - 1] = 1;
}
}
}
printf("All done (successfully read %d words; %d unique words).\n", *total_count, *unique_count);
fflush(stdout);
*word_array = words;
*count_array = counts;
}
int main(int argc, char *argv[])
{
if (argc < 2 || argc > 3)
{
fprintf(stderr, "ERROR: Invalid Arguements\n");
return EXIT_FAILURE;
}
FILE *text_file = fopen(argv[1], "r");
if (text_file == NULL)
{
fprintf(stderr, "ERROR: Can't open file");
return EXIT_FAILURE;
}
int total_count = 0;
int unique_count = 0;
char **word_array = 0;
int *count_array = 0;
file_parse(text_file, &word_array, &count_array, &total_count, &unique_count);
fclose(text_file);
if (argv[2] == NULL)
{
printf("All words (and corresponding counts) are:\n");
fflush(stdout);
for (int i = 0; i < unique_count; i++)
{
printf("%s -- %d\n", word_array[i], count_array[i]);
fflush(stdout);
}
}
else
{
printf("First %d words (and corresponding counts) are:\n", atoi(argv[2]));
fflush(stdout);
for (int i = 0; i < atoi(argv[2]); i++)
{
printf("%s -- %d\n", word_array[i], count_array[i]);
fflush(stdout);
}
}
for (int i = 0; i < unique_count; i++)
free(word_array[i]);
free(word_array);
free(count_array);
return EXIT_SUCCESS;
}
When run on the data file:
the lion's rock. First, the lion woke up
the output was:
Allocated initial parallel arrays of size 8.
Got [the]
Got [lion]
Got [s]
Got [rock.]
Got [First]
Got [the]
Got [lion]
Got [woke]
Got [up]
All done (successfully read 9 words; 7 unique words).
All words (and corresponding counts) are:
the -- 2
lion -- 2
s -- 1
rock -- 1
First -- 1
woke -- 1
up -- 1
When the code was run on your text, including double quotes, like this:
$ echo '"Pardon, O King,"' | cw37 /dev/stdin
Allocated initial parallel arrays of size 8.
Got ["Pardon]
Got [O]
Got [King]
Got ["]
All done (successfully read 3 words; 3 unique words).
All words (and corresponding counts) are:
Pardon -- 1
O -- 1
King -- 1
$
It took a little finnagling of the code. If there isn't an alphabetic character, your code still counts it (because of subtle problems in strip_word()). That would need to be handled by checking strip_word() more carefully; you test if (string == '\0') which checks (belatedly) whether memory was allocated where you need if (string[0] == '\0') to test whether the string is empty.
Note that the code in read_word() would be confused into reporting EOF if there were two commas in a row, or an apostrophe followed by a comma (though it handles a comma followed by an apostrophe OK). Fixing that is fiddlier; you'd probably be better off using a loop with getc() to read a string of characters. You could even use that loop to strip non-alphabetic characters without needing a separate strip_word() function.
I am assuming you've not yet covered structures yet. If you had covered structures, you'd use an array of a structure such as struct Word { char *word; int count; }; and allocate the memory once, rather than needing two parallel arrays.
The code I am working on reads in a dictionary of 45430 words and then prints to the file all the other words in the dictionary contained within each word. I am just working on getting the file MyDictionary txt file read into the char array word[45430][30] and then printing this to the words-in-words txt file. I run into a seg fault at 44946 word when I do so, but in the same while loop I am also printing to the console and all words print out properly. Why is it I am getting this seg fault for writing to the file? And why is there no seg fault writing to the console?
Code:
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <string.h>
//char ***alloc_array(int,int);
int main(void){
FILE *fr; //declare file read file pointer
FILE *fp; //declare file printed file pointer
//char array to read in up to 30 chars
char line[31];
long numwords=45430; //number of words in dictionary
int maxlength=31; // the longest string in dictionary (30 chars)
long i; //counts up to 45430
//allocate space for 45430 words at a max length of 30 chars (1 extra char for "\0")
char ***word = calloc(numwords, sizeof(char **));
for(i = 0; i != numwords; i++) {
word[i] = calloc(maxlength, sizeof(char *));
}
//Open MyDictionary.txt and determine if there is an error or not
fr = fopen ("MyDictionary.txt", "r"); // open the file for reading
if(fr==NULL){
printf("\nError! opening input file");
exit(1); //Program exits if file pointer returns NULL.
}
//Open words-within-words.txt and determine if there is an error or not
fp = fopen ("words-within-words.txt", "w"); // open the file for reading
if(fp==NULL){
printf("\nError! opening output file");
exit(1); //Program exits if file pointer returns NULL.
}
int j=0; //counts to 30 for max length
i=0;
while(fgets(line, 40, fr) != NULL){ //get a line, up to 40 chars from fr and put first . done if NULL
for(j=0;j<30;){
word[i][j]=&line[j];
j++;
}
j=0;
printf("\n%s",word[i][j]); //print out each word of dictionary to console on its own line
/*
if((i>4 && i<8)||(i>45428)){
fprintf(fp,"\nanalyze:word[i][0]=%s\tword[i][2]=%s\ti=%li",word[i][0],word[i][2],i+1);
}
*/
fprintf(fp,"%s",word[i][j]); //print out each word of dictionary to words-in-words on its own line
i++;
}
fclose(fr); //close the files prior to exiting
fclose(fp);
return 0;
} //main
char ***word = calloc(numwords, sizeof(char **));
for(i = 0; i != numwords; i++) {
word[i] = calloc(maxlength, sizeof(char *));
}
You've got one too many levels of indirection. You are storing a list of words. A word is a char *, so a list of words would be char **.
char **word = calloc(numwords, sizeof(char *));
for (i = 0; i != numwords; i++) {
word[i] = calloc(maxlength, sizeof(char));
}
This will then necessitate changes to the rest of your code. You can get rid of j entirely. This:
for(j=0;j<30;){
word[i][j]=&line[j];
j++;
}
Becomes:
strcpy(word[i], line);
And this:
j=0;
printf("\n%s",word[i][j]);
fprintf(fp,"%s",word[i][j]);
i++;
Becomes:
printf("%s\n", word[i]);
fprintf(fp, "%s\n", word[i]);
'word' should be an array of pointers, so the right type is char **, not char ***.
Each entry in the array is a pointer to a buffer of characters:
char **word = (char **)calloc(numwords, sizeof(char *));
if (!word)
// exit with error
for (i = 0; i != numwords; i++) {
word[i] = (char *)calloc(maxlength, sizeof(char)); // just allocate 31 bytes
if (!word[i])
// exit with error
}
Then a read from file can be done like this:
for (i = 0; fgets(line, 40, fr); i++) {
strncpy(word[i], line, maxlength);
printf("word %d: %s\n", i, word[i]);
}
To have one chunk of memory do allocate like this:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int result = EXIT_SUCCESS;
size_t n = 45430;
size_t l = 30;
char (* words)[n][l + 1] = calloc(n, l + 1);
if (NULL == words)
{
result = EXIT_FAILURE;
perror("calloc() failed");
goto lblExit;
}
for (size_t i = 0; i < n; ++i)
{
strncpy((*words)[i], "test", l);
}
for (size_t i = 0; i < n; ++i)
{
printf("%zu: '%s'\n", i, (*words)[i]);
}
free(words);
lblExit:
return result;
}