I'm working on a homework assignment that's supposed to number each line(s) in a file along with the content of the line(s). My teacher briefly mentioned how to free and delete the space we create after we allocate a space but I can't find any of the examples he provided in class. How would I free the space in my code?
#include <stdio.h>
#include <stdlib.h>
#include "read_lines.h"
#include <string.h>
void read_lines(FILE* fp, char*** lines, int* num_lines) {
char letter;
int size = 0;
int sizeOfLines[10000];
int index = 0;
*num_lines = 0;
for(size = 0; !feof(fp);size++){
letter = fgetc(fp);
size++;
if (letter == '\n') {
sizeOfLines[index] = size;
index++;
size = 0;
(*num_lines)++;
}
}
while(!feof(fp)){
letter = fgetc(fp);
size++;
if(letter == '\n'){
sizeOfLines[index] = size;
index++;
size = 0;
(*num_lines)++;
}
}
(*lines) = (char**)malloc(*num_lines *sizeof(char*));
int i = 0;
while (i<*num_lines){
(*lines)[i] = (char *) malloc(sizeOfLines[i] + 1 * sizeof(char));
i++;
}
rewind(fp);
i = 0;
while (i < *num_lines) {
fgets((*lines)[i], (sizeOfLines[i] + 1), fp);
i++;
}
You call function to read lines into file. Good. When you're done with that function, call this one to free the lines.
void free_lines(char** lines, int num_lines)
{
while (num_lines --> 0)
free(lines[num_lines]);
free(lines);
}
Don't just uplift this code. Make sure you understand it.
Assuming your invocation for read_lines looks like this:
char **lines = NULL;
int num_lines = 0;
FILE *fp = fopen(...)
if (fp)
read_lines(fp, &lines, &num_lines);
fclose(fp);
You would invoke free_lines like this:
free_liens(lines, num_lines);
Disclaimer: I haven't tested your read_lines and I have no intention of doing so.
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;
}
again. I'm new to C. Still thinking in Python terms (readlines, append them to variable) so I'm having difficulties translating that to C. This is what I want to do: open a text file for reading, store each line in an array row by row, print it out to make sure it's stored.
This is how far I've got:
int main(){
FILE * fp = fopen("sometext.txt", "r");
char text[100][100];
if(fp == NULL){
printf("File not found!");
}
else{
char aLine[20];
int row = 0;
while(fgets(aLine, 20, fp) != NULL){
printf("%s", aLine);
//strcpy(text[row], aLine); Trying to append a line (as row)
return 0;
}
Please don't start with "invest in some more time and look somewhere else because it's easy and has been answered". I'm bad at this, and I'm trying.
You can try this. Basically you need an array of arrays to store each line. You find the length of the longest line in the file and you allocate space for it. Then rewind the pointer to the start of the file and use fgets to get each line from the file and strdup to allocate space and copy the line to the respective position. Hope this helps.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
FILE * fp = fopen("sometext.txt", "r");
int maxLineSize = 0, count = 0;
char c;
while ((c = fgetc(fp)) != EOF) {
if (c == '\n' && count > maxLineSize) maxLineSize = count;
if (c == '\n') count = 0;
count++;
}
rewind(fp);
char ** lines = NULL;
char * line = calloc(maxLineSize, sizeof(char));
for (int i = 0 ; fgets(line, maxLineSize + 1, fp) != NULL ; i++) { // +1 for \0
lines = realloc(lines, (i + 1) * sizeof(char *));
line[strcspn(line, "\n")] = 0; // optional if you want to cut \n from the end of the line
lines[i] = strdup(line);
printf("%s\n", lines[i]);
memset(line, maxLineSize, '\0');
}
fclose(fp);
}
You could solve it without copy
The follow code could work:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <math.h>
int main()
{
FILE * fp = fopen("sometext.txt", "r");
if(fp == NULL){
printf("File not found!");
return -1;
}
char text[100][20];
int row = 0;
while(row < 100 && fgets(text[row], sizeof(text[0]), fp) != NULL)
++row;
for (int i= 0; i != row; ++i)
fputs(text[i], stdout);
return 0;
}
this is driving me crazy. I'm trying to parse from a txt file every sentence (that is all characters between dots) and insert each sentence into an array. The end goal is to have a multi dimensional array with each sentence as single array.
I managed to reach a point where I think it should work but I'm getting a segmentation fault (core dumped) error from the line numOfRow++
void parseRows(FILE* file){
int c;
int numOfRow = 0;
int numOfChar = 0;
int numOfRows = countNumOfRows(file);
fseek(file, 0, SEEK_SET); // Reset file pointer position to the beginning
char **rows = malloc(numOfRows*sizeof(char*));
for (int i=0; i < numOfRows; i++) rows[i] = malloc(1000*sizeof(char));
while ((c=fgetc(file))!= EOF) {
if (c != '.') {
rows[numOfRow][numOfChar] = c;
numOfChar++;
} else {
rows[numOfRow][numOfChar] = '\0';
numOfRow++; // This is throwing the error
numOfChar = 0;
}
}
printOutput(rows, numOfRows);
}
If I comment out that line the program overwrites every line on the first array and I get only the last sentence as result so I know it's working.
What am I missing?
Complete code here:
#include <stdio.h>
#include <stdlib.h>
#define USAGE "USAGE: ./huffman <textFile.txt>\n"
FILE* openFile(char[]);
void parseRows(FILE*);
int countNumOfRows(FILE*);
void printOutput(char**, int);
int main(int argc, char** argv){
FILE* fd;
if (argc != 2) printf("%s", USAGE);
fd = openFile(argv[1]);
parseRows(fd);
}
FILE* openFile(char* file){
FILE* stream;
stream = fopen(file, "r");
return stream;
}
int countNumOfRows(FILE* file){
int i = 0;
char c;
while ((c=fgetc(file))!= EOF) {
if (c == '.') i++;
}
printf("numero di righe %d\n", i);
return i;
}
void parseRows(FILE* file){
int c;
int numOfRow = 0;
int numOfChar = 0;
int numOfRows = countNumOfRows(file);
fseek(file, 0, SEEK_SET); // Reset file pointer position to the beginning
char **rows = malloc(numOfRows*sizeof(char*));
for (int i=0; i < numOfRows; i++) rows[i] = malloc(1000*sizeof(char));
while ((c=fgetc(file))!= EOF) {
if (c != '.') {
rows[numOfRow][numOfChar] = (char)c;
numOfChar++;
} else {
rows[numOfRow][numOfChar] = '\0';
numOfRow += 1;
numOfChar = 0;
}
}
printOutput(rows, numOfRows);
}
void printOutput(char** matrix, int rows){
for (int i=0; i<rows; i++){
printf("%s", matrix[i]);
}
}
Example of input file textFile.txt:
Any text that contains more than one sentence.
This Should get parsed and return a 2 dimension array with every sentence as single array.
Your countNumOfRows() function counts the dots in a file, and you use that number to malloc space for your array. However, there are likely more characters beyond the last dot and before EOF (e.g. a CR or LF or CRLF), so you can easily write past the end of your malloc'd memory.
Try:
return (i + 1)
at the end of countNumOfRows() and see if that eliminates the segfault.
I try to read in a file multiple times instead of just once.
While trying that I got alot of segementation faults. The part of the program with the while loop looks like this:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
/* General use buffer */
#define STRLEN 8196
char string[STRLEN];
int lines = 1024;
char **line;
int linemax;
int longest=0;
int main(){
int len,i;
int zwei = 1;
FILE * fp;
char *s;
int debug = 0;
line=(char **)malloc(sizeof(char *) * 1024);
do{
if ( (fp = fopen("rhel7_160731_0606.nmon", "r")) == NULL) {
perror("failed to open file");
perror("fopen");
exit(75);
}
printf("where is the problem1,3\n");
for (i = 0; fgets(string, STRLEN, fp) != NULL; i++) {
if (i >= lines) {
lines += 1024;
line = (char **)realloc((void *)line, sizeof(char *) * lines);
}
if (string[strlen(string)-1] == '\n')
string[strlen(string)-1] = 0;
if (string[strlen(string)-1] == '\r')
string[strlen(string)-1] = 0;
if (string[strlen(string)-1] == ' ')
string[strlen(string)-1] = 0;
if (string[strlen(string)-1] == ',')
string[strlen(string)-1] = 0;
len = strlen(string) + 1;
if (len > longest)
longest = len;
s = malloc(len);
strcpy(s, string);
line[i] = (char *)s;
}
linemax = i;
lines = i;
if (debug)
for (i = 0; i < linemax; i++)
printf("line %d lastline %s\n", i, line[i-1]);
zwei++;
}while(zwei<4);
return 0;
}
It hangs nothing or ends with a segmentation fault.
You seem to have forgotten to allocate memory for line. It fails here: line[i] = (char *)s. I think you need to set lines to zero, since you reallocate line only if your iterator i gets grower than lines.
Also, fix this: while(zwei > 4) to while(zwei < 4). And, you need to free the memory you allocate - because you store all the pointers in line, it is not going to be complicated - just one loop.
i'm trying to read lines of a file. txt, but without knowing the size of each lines...First I used the getline instruction (and works fine), but my teacher does not let me use that instruction, he says I can only use the fgets statement with malloc and realloc...
This is an input example, with variable line sizes:
[9.3,1.2,87.9]
[1.0,1.0]
[0.0,0.0,1.0]
As shown, each line defines a different vector with no size limit
Someone could help me implement this method?
Thank you very much.
NOTE: I forgot to mention, to compile the program I use these commands:
g++ -Wall-Wextra-Werror-pedantic main.c-o metbasicos.c metintermedios.c eda.exe
./eda.exe <eda.txt
I would say do something similar to this
while(fgets(buf, LEN, stdin)){
z = strtok(buf, ",");
*(*(matrix + i)) = atof(z);
for(j = 1; j < col; ++j){
z = strtok(NULL, ",");
*(*(matrix + i) + j) = atof(z);
}
++i;
}
The only extra thing you would have to take care of is making sure that you strip the brackets off of the first and last element.
Of course, if you don't know the size of the final array, you might need something like this:
struct data_t {
int nval; /* current number of values in array */
int max; /* allocated number of vlaues */
char **words; /* the data array */
};
enum {INIT = 1, GROW = 2};
...
while (fgets(buf, LEN, stdin)) {
if (data->words == NULL)
data->words = malloc(sizeof(char *));
else if (data->nval > data->max) {
data->words = realloc(data->words, GROW * data->max *sizeof(char *));
data->max = GROW * data->max;
}
z = strtok(buf, "\n");
*(data->words + i) = malloc(sizeof(char) * (strlen(z) + 1));
strcpy(*(data->words + i), z);
i++;
data->nval++;
}
data->nval--;
If you combine both of those while loops into a single one, you should be all set. The first one reads in floats, the second one is good for dynamically allocating space on the fly.
If you can use multiple steps, then use one function to get the information you need to malloc memory. (for example determine number of lines, and longest line) This function will do that for you (given the file name and location)
[EDIT] LineCount - This function will get you the number of lines, and the longest line so you can dynamically allocate memory in char **strings; in which to read the lines of the input file.
int lineCount(char *file, int *nLines)
{
FILE *fp;
int cnt=0, longest=0, numLines=0;
char c;
fp = fopen(file, "r");
while ( (c = fgetc ( fp) ) != EOF )
{
if ( c != '\n' )
{
cnt++;
if (cnt > longest) longest = cnt;
}
else
{
numLines++;
cnt= 0;
}
}
*nLines = numLines+1;//add one more
fclose(fp);
return longest+1;
}
Here is the implementation to read the input file you provided, using the function above to get the unknown dimensions of the input file...
#include <ansi_c.h>
#include <stdio.h>
#define FILENAME "c:\\dev\\play\\in.txt" //put your own path here
#define DELIM "- ,:;//_*&[]\n" //change this line as needed for search criteria
int lineCount(char *file, int *cnt);
void allocMemory(int numStrings, int max);
void freeMemory(int numStrings);
char **strings;
int main()
{
int numLines, longest, cnt, i;
FILE *fp;
longest = lineCount(FILENAME, &numLines);
char wordKeep[longest];
allocMemory(numLines, longest);
//read file into string arrays
fp = fopen(FILENAME, "r");
cnt=0;
i=0;
for(i=0;i<numLines;i++)
{
fgets(strings[i], longest, fp);
}
fclose(fp);
freeMemory(numLines);
getchar();
return 0;
}
int lineCount(char *file, int *nLines)
{
FILE *fp;
int cnt=0, longest=0, numLines=0;
char c;
fp = fopen(file, "r");
while ( (c = fgetc ( fp) ) != EOF )
{
if ( c != '\n' )
{
cnt++;
if (cnt > longest) longest = cnt;
}
else
{
numLines++;
cnt= 0;
}
}
*nLines = numLines+1;//add one more
fclose(fp);
return longest+1;
}
void allocMemory(int numStrings, int max)
{
int i;
// need number of lines by longest line for string containers
strings = calloc(sizeof(char*)*(numStrings+1), sizeof(char*));
for(i=0;i<numStrings; i++)
{
strings[i] = calloc(sizeof(char)*max + 1, sizeof(char));
}
}
void freeMemory(int numStrings)
{
int i;
for(i=0;i<numStrings; i++)
if(strings[i]) free(strings[i]);
free(strings);
}