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.
Related
I've been developing a guessing game in which the goal is to guess the character selected by the user among specific characters, anyway, my first and only idea is to create an array with the questions to be asked, and each question has its options like in the code below I'm a newbie in C language so that I there are several things which I'm not sure how to handle. In short, I'd like to know how can I loop over the array showing to the user the questions with its questions to be answered? Here's the code.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define ROW 500
#define LINE 200
//Read file and append to an array buffer
char *characters(){
char *source = NULL;
FILE *fp = fopen("file.txt", "r");
if (fp != NULL) {
/* Go to the end of the file. */
if (fseek(fp, 0L, SEEK_END) == 0) {
/* Get the size of the file. */
long bufsize = ftell(fp);
if (bufsize == -1) { /* Error */ }
/* Allocate our buffer to that size. */
source = malloc(sizeof(char) * (bufsize + 1));
/* Go back to the start of the file. */
if (fseek(fp, 0L, SEEK_SET) != 0) { /* Error */ }
/* Read the entire file into memory. */
size_t newLen = fread(source, sizeof(char), bufsize, fp);
if ( ferror( fp ) != 0 ) {
fputs("Error reading file", stderr);
} else {
source[newLen++] = '\0'; /* Just to be safe. */
}
}
fclose(fp);
}
return source;
}
char *strndup(const char *s, size_t n) {
char *p;
size_t n1;
for (n1 = 0; n1 < n && s[n1] != '\0'; n1++)
continue;
p = malloc(n + 1);
if (p != NULL) {
memcpy(p, s, n1);
p[n1] = '\0';
}
return p;
}
// User input
char *input(){
char *value;
char buffer[10];
int j = 0;
while( j < 1 && fgets(buffer, 10, stdin) != NULL){
value = strndup(buffer, 10);
j++;
}
return value;
}
// Main function
int main (void)
{
char *questions[] = {
"Genre",{"male","female"},
"Hair", {"black","red","blond"},
"Cloths",{"dress","shirt","pants"},
"pet", {"dog","cat","pig"}
};
int asked[4] = {0};
char *answers[5];
char buffer[6];
srand(time(NULL));
for (int i = 0; i < 4; i++) {
int q = rand() % 4;
while (asked[q])
q = rand() % 4;
asked[q]++;
printf ("%s\n", questions[q]);
answers[i] = input();
}
for(int i = 0; i < 4; i++)
{
printf(" %s ",answers[i]);
}
return 0;
}
That's the file's structure I'll compare as long as I have all the answers from the user.
female,blond,vestido,pig,character b
male,black,shirt,pants,dog,character c
male,black,shirt,pants,cat,character d
female,blond,dress,cat,character A
male,red,shirt,pants,pig,character e
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.
I've been trying to run this code on VS2017. The code is compiling and running, but not in the way I want it too. So, I try to use the debugger and it says:
Debug Assertion Failed!
Program:
File: minkernel\crts\ucrt\src\appcrt\stdio\fgets.cpp
Line:33
Expression: stream.valid()
From past questions I understood that it may happen because of mishandling the opening of files, but I think that my code does take care of it.
Any help would be greatly appreciated!
(my relevant code):
int main(int argc, char *argv[]) {
int i, count_commands, PC_A, lastLine;
int *PC = &PC_A;
FILE *memin;
FILE *memout;
FILE *regout;
FILE *trace;
FILE *count;
assert(argc == 6);
*PC = 0;
count_commands = 0;
//allocationg memory for registers content
char **regs = (char **)(malloc(sizeof(char *) * 16));
for (i = 0; i < 16; i++) {
regs[i] = (char *)(malloc(sizeof(char) * 9));
for (int j = 0; j < 8; j++) {
regs[i][j] = '0';
}
regs[i][8] = '\0';
}
//allocationg memory for the memory image we have
char **memory = (char **)(malloc(sizeof(char *) * 4096));
for (i = 0; i < 4096; i++) {
memory[i] = (char *)(malloc(sizeof(char) * 9));
memory[i][0] = '\0';
}
//load memin image into memory
char *line = (char *)malloc(sizeof(char) * 8);
memin = fopen(argv[1], "r");
if (memin != NULL) {
perror(strerror(errno));
}
int j = 0;
while ((line = fgets(line, 10, (FILE *)memin)) != NULL) {
strcpy(memory[j], line);
memory[j][8] = '\0';
j++;
}
After opening the file, in OP's code there is this check:
if (memin != NULL) {
perror(strerror(errno));
}
So, if the opening succeeded an error string is printed. In my implementation, it reports:
Success: Success
No action is taken if it fails to open the file.
When it comes to the actual reading of all the lines in the file, there are some other issues. A buffer (char array) named line of size 8 is dinamically allocated and passed to fgets:
while ((line = fgets(line, 10, (FILE *)memin)) != NULL) {
// ^^
Note that 10 is also passed, as size of the buffer, which is wrong, because it allows fgets to write out of the bounds of the allocated array.
Also, given OP's compiler is MSVC 2017, I assume this code is running on Windows, so chances are that in the file, the lines are terminated by a "\r\n" sequence, rather then a single '\n'. Even if OP is confident that each line is a 8 char string, fgets needs a buffer of at least size 8 + 3 (8 + '\r' + '\n' + '\0') to read them safely.
Consider how those suggestions are implemented in this snippet:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define MEM_SIZE 1024u
#define LINE_SIZE 128u
#define STR_SIZE 8u
int main(int argc, char *argv[])
{
// Try to open the input file
if (argc < 2) {
fprintf(stderr, "Missing file name in command line.\n");
return EXIT_FAILURE;
}
FILE *memin = fopen(argv[1], "r");
if (memin == NULL) {
fprintf(stderr, "Unable to open file [%s].\n", argv[1]);
return EXIT_FAILURE;
}
// I'd use plain arrays to store the lines
char memory[MEM_SIZE][STR_SIZE + 1] = {{'\0'}};
char line[LINE_SIZE] = {'\0'};
size_t count = 0;
while ( count < MEM_SIZE && fgets(line, LINE_SIZE, memin) ) {
size_t length = strcspn(line, "\r\n");
if (length > STR_SIZE) {
fprintf(stdout, "Warning, line too long: %zu.\n", count);
length = STR_SIZE;
}
memcpy(memory[count], line, length);
memory[count][STR_SIZE] = '\0';
++count;
}
for ( size_t i = 0; i < count; ++i ) {
printf("[%s]\n", memory[i]);
}
}
I want to read the txt line by line and store it to the array;
I am like success to store line by line in array;
I use printf("%s", loadtext[i]) with i= 0,1,2,3-20 respectively to check that things in stored in array;
but I realize that the for loop had done 1912 times when I
type printf("%d", i); right behind the for loops,
Suppose my txt is store like this:
I am a jerk
I am a noob
I am an idiot
I am done
I have another program to add new lines to the text file while this program is running.
How can I detect I am done or the new line added later is the last line to not allow the for loop do so many times?
Here is my code
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <string.h>
int main(){
FILE *fp = fopen("abc.txt","r");
int i = 0,j=0,k=0;
char ch[10000];
char loadtext[100][100];
for (i=0; ch[i] != EOF; i++){
ch[i] = fgetc(fp);
if (ch[i] != '\n'){
loadtext[j][k] = ch[i];
k++;
}
if(ch[i] == '\n'){
loadtext[j][k] = ch[i];
k=0;
j++;
}
}
printf("%s", loadtext[0]);
printf("%s", loadtext[1]);
printf("%s", loadtext[2]);
fclose(fp);
return 0;
}
To read a whole file into an "array" of pointers to char which represent the lines, you can do:
#include <stddef.h> // size_t
#include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE
#include <stdio.h> // malloc(), realloc(), free(), fgets()
#include <string.h> // strlen(), strcpy()
enum { BUFFER_SIZE = 30 }; // whatever line length you suspect the input file to be + 1
int main(void)
{
char const *filename = "test.txt";
FILE *is = fopen(filename, "r");
if (!is) {
fprintf(stderr, "Couldn't open \"%s\" for reading :(\n\n", filename);
return EXIT_FAILURE;
}
int result = EXIT_SUCCESS; // assume a happy ending
char buffer[BUFFER_SIZE];
size_t num_lines = 0;
char **lines = NULL;
while (fgets(buffer, sizeof(buffer), is)) {
++num_lines;
char **temp = realloc(lines, num_lines * sizeof(*lines));
if (!temp) {
fputs("Not enough memory :(\n\n", stderr);
fclose(is);
result = EXIT_FAILURE;
goto cleanup;
}
lines = temp;
size_t length = strlen(buffer);
length = strlen(buffer);
// remove a trailing newline if any:
if (length && buffer[length - 1] == '\n')
buffer[--length] = '\0';
size_t line_length = length;
lines[num_lines - 1] = malloc((length + 1) * sizeof(*lines));
if (!lines[num_lines - 1]) {
fputs("Not enough memory :(\n\n", stderr);
fclose(is);
result = EXIT_FAILURE;
goto cleanup;
}
strcpy(lines[num_lines - 1], buffer);
// as long as the buffer has been filled completely by the previous
// call to fgets() and a next call to fgets() also succeeds:
while (length == BUFFER_SIZE - 1 && fgets(buffer, sizeof(buffer), is)) {
length = strlen(buffer);
// remove a trailing newline if any:
if (length && buffer[length - 1] == '\n')
buffer[--length] = '\0';
char *temp = realloc(lines[num_lines - 1], line_length + length + 1);
if (!temp) {
fputs("Not enough memory :(\n\n", stderr);
fclose(is);
result = EXIT_FAILURE;
goto cleanup;
}
lines[num_lines - 1] = temp;
strcpy(lines[num_lines - 1] + line_length, buffer);
line_length += length;
}
}
fclose(is);
// use lines:
for (size_t i = 0; i < num_lines; ++i)
puts(lines[i]);
cleanup:
for (size_t i = 0; i < num_lines; ++i)
free(lines[i]);
free(lines);
return result;
}
Using only a fixed-size two-dimensional array and fgetc()*):
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
enum { MAX_LINES = 100, MAX_LINE_LENGTH = 100 };
int main(void)
{
char const *filename = "test.txt";
FILE *is = fopen(filename, "r");
if (!is) {
fprintf(stderr, "Couldn't open \"%s\" for reading :(\n\n", filename);
return EXIT_FAILURE;
}
char text[MAX_LINES][MAX_LINE_LENGTH + 1] = { 0 }; // zero-initialize the array
// so we don't have to care
size_t num_lines = 0; // about zero terminating
size_t current_column = 0; // every line
int ch;
// as long as we are still inside the bounds of the fixed size array
// and fgetc() doesn't return EOF
while (num_lines < MAX_LINES && current_column < MAX_LINE_LENGTH &&
(ch = fgetc(is)) != EOF)
{
if (ch == '\n') { // "move" num_lines and current_column to the next
++num_lines; // line.
current_column = 0;
continue;
}
text[num_lines][current_column++] = ch;
}
if (ch != EOF) {
fputs("The file is too big :(\n\n", stderr);
return EXIT_FAILURE;
}
for (size_t i = 0; i <= num_lines; ++i)
puts(text[i]);
}
*) Could be done with fgets() too.
to read the txt line by line and store it to the array
Code has various problems:
ch[i] != EOF accesses ch[i] before it is assigned! Undefined Behavior (UB).
char can be signed or unsigned. EOF is some negative. When char is unsigned the below is an infinite loop. When char is signed, ch[i] != EOF could exit the loop early.
printf("%s", loadtext[0]); attempts to print loadtext[0] as if it was a string. But lacking a certain null character, and thus not a string, this leading to more UB.
Lack of buffer index checks: loadtext[j][k] = ch[i]; k++; may increment k to beyond 100. Similar weak code with i.
Code may fail to open the file and no check provided.
Instead save the result from fgetc() as an int, test for for EOF, test for '\n' and append a null character to form strings.
Some ideas for alternate code:
#define LINES_N 100
#define LINE_SIZE 100
int main(void) {
FILE *fp = fopen("abc.txt", "r");
if (fp) {
// char ch[10000];
char loadtext[LINES_N][LINE_SIZE];
int ch_index = 0;
int line_count = 0;
int character;
int previous_character = '\n';
while ((character = fgetc(fp)) != EOF) {
// Starting a new line?
if (previous_character == '\n') {
if (++line_count > LINES_N) {
printf("Too many lines\n");
return EXIT_FAILURE;
}
}
loadtext[line_count - 1][ch_index++] = (char) character;
loadtext[line_count - 1][ch_index] = '\0';
if (ch_index + 1 >= LINE_SIZE) {
printf("Too long a line\n");
return EXIT_FAILURE;
}
previous_character = character;
}
if (line_count >= 1) printf("%s", loadtext[0]);
if (line_count >= 2) printf("%s", loadtext[1]);
if (line_count >= 3) printf("%s", loadtext[2]);
fclose(fp);
}
return 0;
}
I am writing a UNIX paste clone. However I keep getting "encountered a breakpoint" messages, but VS won't tell me on what line it happened.
#include <stdio.h>
#include <stdlib.h>
#define INITALLOC 16
#define STEP 8
int main(int argc, char *argv[])
{
if (horzmerge(argc - 1, argv + 1) == 0) {
perror("horzmerge");
return EXIT_FAILURE;
}
getchar();
return EXIT_SUCCESS;
}
int horzmerge(int nfiles, const char **filenames)
{
FILE **files;
char *line;
int i;
if ((files = malloc(nfiles * sizeof (FILE *))) == NULL)
return 0;
for (i = 0; i < nfiles; ++i)
if ((files[i] = fopen(filenames[i], "r")) == NULL)
return 0;
do {
for (i = 0; i < nfiles; ++i) {
if (getline(files[i], &line) == 0)
return 0;
fprintf(stdout, "%s", line);
free(line);
}
putchar('\n');
} while (!feof(files[0])); /* we can still get another line */
for (i = 0; i < nfiles; ++i)
fclose(files[i]);
free(files);
return 1;
}
int getline(FILE *fp, char **dynline)
{
size_t nalloced = INITALLOC;
int c, i;
if ((*dynline = calloc(INITALLOC, sizeof(char))) == NULL)
return 0;
for (i = 0; (c = getc(fp)) != EOF && c != '\n'; ++i) {
if (i == nalloced)
if ((*dynline = realloc(*dynline, nalloced += STEP)) == NULL)
return 0;
(*dynline)[i] = c;
}
(*dynline)[i] = '\0';
if (c == EOF)
return EOF;
return i;
}
I placed breakpoints, and saw that it was the free(line) statement in horzmerge. But sometimes the program runs fine. Sometimes it doesn't. Sometimes I get a "Heap corrupted" in getline. I've been working on this code for a week, still can't find the bug(s).
It looks to me like the line where you null-terminate the input string is capable of overrunning the buffer you calloced or realloced. That has the potential of corrupting your heap when you free that buffer.
Dont't forget to leave room for the null character at the end of the string when you allocate memory.
Null-terminated strings are like disco. They still suck forty years later.