Reading and writing from files with a new form - c

I'm trying to read from a file and I have to use a new form of it I'm not really certain how to use. I've posted the code below of what function I have and I'm not sure what to do about this error and how to fix it?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
double* read_file(FILE* file, int length);
int main(int argc, char* argv[])
{
double* array = malloc(10 * sizeof(double));
int length = atoi(*(argv + 1));
FILE* file = *(argv + 2);
if (argc < 4 || argc > 4)
{
printf("Insufficient arguments. Check your command line.\n");
return 0;
}
array = read_file(file, length);
printf("%p", array);
return 0;
}
double* read_file (FILE* file, int length)
{
FILE* ptr;
double* array = malloc(length * sizeof(double));
int i = 0;
if ((ptr = fopen(file, "r")) == NULL)
{
return 0;
}
else
{
for (i = 0; i < length; i++)
{
fscanf(ptr, "%lf", (array + i));
}
}
fclose(ptr);
return array;
}

First of all, you're trying to assign a char string to a variable of type pointer to FILE. The compiler won't let you do that.
// not allowed
FILE* file = *(argv + 2);
Secondly, you're passing a pointer to FILE to fopen(), but fopen() expects it's first argument to be a char string so that won't work either.
// file is FILE*, not allowed
ptr = fopen(file, "r"));
If you fix those two lines the code should compile.

fix like this
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//double* read_file(FILE* file, int length);
//You do not need to pass a file pointer, you need a file name.
//It opens the file within this function
double *read_file(const char *filename, int length);
int main(int argc, char* argv[]){
//if (argc < 4 || argc > 4)
//argc < 4 || argc > 4 same as argc != 4
//It is thought that it is 3 because only argv[1] and argv[2] are used.
//It is necessary to check arguments before using them.
if (argc != 3) {
printf("Usage : %s number_of_elements file_name\n", argv[0]);
printf("Insufficient arguments. Check your command line.\n");
return 0;
}
//double* array = malloc(10 * sizeof(double));//It is not necessary as it is secured by read_file. Make memory leak.
int length = atoi(argv[1]);
const char *file = argv[2];
double *array = read_file(file, length);
if(array != NULL){
for(int i = 0; i < length; ++i)
printf("%f\n", array[i]);
free(array);
}
return 0;
}
double* read_file (const char *file, int length){
FILE *ptr;
if ((ptr = fopen(file, "r")) == NULL){
return NULL;
}
//It causes a memory leak unless you first confirm that the file can be opened
double *array = malloc(length * sizeof(double));
for (int i = 0; i < length; i++){
if(1 != fscanf(ptr, "%lf", array + i)){
printf("Failed to read the %ith element.\n", i+1);
break;
}
}
fclose(ptr);
return array;
}

Related

Update array of strings in function

I have a working example of copy lines from a file into an array of strings. I want to move the code to copy the lines into a function to which I simply pass a pointer to the array of strings, where the lines will be stored, and a pointer to the file. However, I have tried to move the code into a function and keep getting seg faults. I have tried debugging using GDB and it seems like the problem is with the memory allocation to rows. But I can't work out what the problem is. realloc seems to be working correctly since I find the size of row increases on the 3rd iteration (using malloc_usable_size(*rows)), but then seg faults. I'm compiling with gcc -Wall -Wextra -pedantic -std=c99 -g c_programs/read_file_function.c on Linux.
Working example
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Please supply a file path:\n%s <file path>\n", argv[0]);
return EXIT_FAILURE;
}
FILE *fp = fopen(argv[1], "r");
if (!fp)
{
perror("ERROR");
return EXIT_FAILURE;
}
char **rows = (char **)malloc(sizeof(char *));
char *lineBuf = NULL;
size_t n = 0;
size_t nLines = 0;
ssize_t lineLength = 0;
size_t i = 0;
while ((lineLength = getline(&lineBuf, &n, fp)) != -1)
{
lineBuf[strcspn(lineBuf, "\n")] = 0;
lineBuf[strcspn(lineBuf, "\r")] = 0;
rows[i] = (char *)malloc(lineLength + 1);
strcpy(rows[i], lineBuf);
i++;
nLines = i;
rows = (char **)realloc(rows, (nLines + 1) * sizeof(char *));
}
printf("nLines: %lu\n", nLines);
printf("row 1: %s\n", rows[0]);
printf("row 2: %s\n", rows[1]);
printf("row 2: %s\n", rows[10]);
return 0;
}
Non working function version
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
size_t readFile(FILE **fp, char ***rows)
{
char *lineBuf = NULL;
size_t n = 0;
size_t nLines = 0;
ssize_t lineLength = 0;
size_t i = 0;
while ((lineLength = getline(&lineBuf, &n, *fp)) != -1)
{
lineBuf[strcspn(lineBuf, "\n")] = 0;
lineBuf[strcspn(lineBuf, "\r")] = 0;
*rows[i] = (char *)malloc(lineLength + 1);
strcpy(*rows[i], lineBuf);
i++;
nLines = i;
*rows = (char **)realloc(*rows, (nLines + 1) * sizeof(char *));
}
return nLines;
}
int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Please supply a file path:\n%s <file path>\n", argv[0]);
return EXIT_FAILURE;
}
FILE *fp = fopen(argv[1], "r");
if (!fp)
{
perror("ERROR");
return EXIT_FAILURE;
}
char **rows = (char **)malloc(sizeof(char *));
size_t nLines = readFile(&fp, &rows);
printf("nLines: %lu", nLines);
printf("row 1: %s", rows[0]);
printf("row 2: %s", rows[1]);
return 0;
}
*rows[i] is doing *(rows[i]) - accessing ith element in the array of rows, and then dereferencing it. You want to do (*rows)[i] - dereference rows and then access ith element.
I advise to:
readFile(..., char ***rows0) {
char **rows = NULL; // temporary internal variable
...
// use rows normally
rows = stuff();
...
// when finished, assign once
*rows0 = rows;
return nLines;
}
But do not be a 3-star programmer. At best, use a structure, -> is easy to use. Like:
struct string {
char *str;
};
struct lines {
struct string *strs;
size_t cnt;
};
// #return 0 on success, otherwise error
int readFile(...., struct lines *p) {
// initialization
p->cnt = 0;
p->strs = NULL;
...
void *pnt = realloc(p->strs, (p->cnt + 1) * ....);
if (!pnt) { /* handle error */ return -1; }
p->strs = pnt;
p->strs[p->cnt]->str = malloc(lineLenght + 1);
if (!p->strs[p->cnt]->str) { /* handle error */ return -2; }
strcpy(p->strs[p->cnt]->str, lineBuf);
p->cnt++;
...
return 0; /* success */
}
int main(int argc, char **argv) {
struct lines p = {0};
if (readFile(..., &p)) {
/* handle error */
}
printf("nLines: %zu\n", p.cnt);
Do not pre-allocate memory. Initialize memory with NULL and call realloc before using memory. realloc(NULL is the same as malloc().
Check for allocation errors.

Seg fault from within my print function after reading in a file in c

I have an unknown segfault within my print function when I call it in main and I can't see what the obvious fix is. I have put printf's throughout the program and it doesn't print 'here4' making me think it's due to my print function, or when I call it in main.
I want to read a dictionary file into an array of strings.
Here is a snippet of the code:
Any ideas would be greatly appreciated, thanks.
#define PRIME 1009
void fileRead(int argc, char **argv)
void printTable(int arrayLength, char **table);
int main(int argc, char **argv)
{
char **table;
FILE *fp;
int i, arrayLength = PRIME;
/* Initial memory allocation */
table = (char**)malloc(PRIME*sizeof(char));
fileRead(argc, argv);
printf("here3\n");
for(i = 0; i < arrayLength; i++) {
printTable(arrayLength,table);
}
printf("here4\n");
return 0;
}
void fileRead(int argc, char **argv)
{
FILE *fp;
char *word;
int arrayLength = PRIME;
word = calloc(MAXCHAR, sizeof(char));
fp = fopen (argv[1], "r");
printf("here1\n");
/*read in grid and move along a cell each time */
while (fscanf(fp, "%s", word)!= EOF) {
if (argc != (2)) {
fprintf(stderr, "Cannot open file, %s\n Try again e.g. %s dictionary.txt\n" , argv[1], argv[0]);
}
if(fp == NULL) {
fprintf(stderr, "Cannot open file, %s\n Try again e.g. %s dictionary.txt\n" , argv[1], argv[0]);
return;
}
if (fp == NULL) {
fprintf(stderr, "Error opening file, try file name dictionary.txt\n");
exit(EXIT_FAILURE);
}
}
printf("here2\n");
fclose(fp);
return;
}
void printTable(int arrayLength, char **table)
{
int i;
for(i = 0; i < arrayLength; i++) {
printf("%s\n", table[i]);
}
printf("\n");
}
Let me summarize your code:
you allocate uninitialized memory for table
You call a function fileRead():
Allocate some memory for word
read the file
Do nothing with the data read.
fileRead() does nothing useful: It does not return anything, it doesn't touch table, is vulnerable to a buffer overflow of word and leaves the memory leak of word behind.
And then you printf the unchanged and uninitialized content of table
try this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PRIME 1009
#define MAXCHAR 256
char **fileRead(FILE *fp, int *len);
void printTable(int arrayLength, char **table);
int main(int argc, char **argv){
if (argc != 2) {
fprintf(stderr, "Need dictionary file argument.\nTry again e.g. %s dictionary.txt\n" , argv[0]);
exit(EXIT_FAILURE);
}
FILE *fp = fopen (argv[1], "r");
if(fp == NULL) {
fprintf(stderr, "Cannot open file, %s\nTry again e.g. %s dictionary.txt\n" , argv[1], argv[0]);
exit(EXIT_FAILURE);
}
int arrayLength = PRIME;
char **table = fileRead(fp, &arrayLength);//fclose(fp) inside this
printTable(arrayLength, table);
for(int i = 0; i < arrayLength; ++i)
free(table[i]);
free(table);
return 0;
}
char **fileRead(FILE *fp, int *len){
char *word = calloc(MAXCHAR, sizeof(char));
char **table = malloc(*len * sizeof(char*));
int i = 0;
while (i < *len && fscanf(fp, "%s", word) != EOF){
table[i] = malloc(strlen(word)+1);
strcpy(table[i++], word);
}
fclose(fp);
*len = i;
free(word);
return table;
}
void printTable(int arrayLength, char **table){
int i;
for(i = 0; i < arrayLength; i++) {
printf("%s\n", table[i]);
}
printf("\n");
}

How to use pointers to return 2D arrays functions?

So I have a function called scanCode which scans words from a text file and stores it in a 2D array. I then want to return this array into an array variable in the main function, this is my code so far
#include <stdio.h>
char **scanCode()
{
FILE *in_file;
int i = 0;
static char scan[9054][6];
in_file = fopen("message.txt", "r");
while (!feof(in_file))
{
fscanf(in_file, "%s", scan[i]);
i++;
}
return scan;
}
int main(void)
{
int hi[9053];
FILE *in_file;
in_file = fopen("message.txt", "r");
char **array = scanCode();
printf("%c", array[0]);
printf("%c", array[1]);
printf("%c", array[2]);
printf("%c", array[3]);
}
So basically the array returned from the scanCode function I want it to be stored in the char array in the main function.. after looking at a lot of questions and answers here, this is what I got to but the pointer etc is hard to understand for me.. could someone tell me what I did wrong here?
Change the return type of the function the following way
#include <stdio.h>
char ( *scanCode() )[6]
{
FILE *in_file;
int i = 0;
static char scan[9054][6];
in_file = fopen("message.txt", "r");
while (!feof(in_file))
{
fscanf(in_file, "%s", scan[i]);
i++;
}
return scan;
}
int main(void)
{
int hi[9053];
FILE *in_file;
in_file = fopen("message.txt", "r");
char ( *array )[6] = scanCode();
printf("%s", array[0]);
printf("%s", array[1]);
printf("%s", array[2]);
printf("%s", array[3]);
}
Also in the printf statements use format specifier %s
And change the loop in the function like
while ( i < 9054 && fscanf(in_file, "%5s", scan[i]) == 1 ) ++i;
I prefer to simplify the code in this way:
#include <stdio.h>
#define NumLines 9054
#define NumCols 6
void freeMem(char **ele) {
while (*ele != NULL) {
free(*ele);
ele++;
}
}
char **scanCode(char *fileName)
{
FILE *in_file;
char readingFormat[128];
int i = 0;
/*
* Instead to declare a static variable I prefer to allocate dynamically
* the bidimensional array.
* It is done in two steps:
* 1. allocate the memory for the first dimension
* 2. for each element in this dimension allocate the memory for each element in the second dimension
*
*/
char **scan = (char **)malloc((NumLines + 1) * sizeof(char *));
if (scan == NULL) {
return NULL;
}
for (int j = 0; j < NumLines; j++) {
scan[j] = (char *)malloc(NumCols + 1);
if (scan[j] == NULL) {
freeMem(scan);
return NULL;
}
scan[j][0] = NULL;
}
scan[NumLines] = NULL; // define the end of memory
in_file = fopen(fileName, "r");
if (fopen == NULL) {
freeMem(scan);
return NULL;
}
sprintf(readingFormat, "%%%ds", NumCols);
while (fscanf(in_file, readingFormat, scan[i]) == 1 && i < NumLines) {
i++;
}
return scan;
}
int main(void)
{
char **array = scanCode("message.txt");
if (array == NULL) {
printf("ERROR\n");
exit(0);
}
for (char **tp = array; **tp != NULL; tp++) {
printf("%s\n", *tp);
}
}
Arrays aren't pointers (hello from me again).
This:
static char scan[9054][6];
have the most obvious type you would expect it to be - 'char [9054][6]' and not 'char **'. It's spelled as an array of 6 elements each of which is another array of 9054 chars. On the other hand the type 'char **' is spelled as 'a pointer to pointer to char' and as you can probably see now they are entirely different things.
Your code should look something like this:
#include <stdio.h>
typedef char yourArrayType[9054][6];
typedef struct { yourArrayType return_value; } letsReturnArraysType;
letsReturnArraysType scanCode()
{
FILE *in_file;
int i = 0;
yourArrayType scan;
in_file = fopen("message.txt", "r");
while (!feof(in_file))
{
fscanf(in_file, "%s", scan[i]);
i++;
}
return *(letsReturnArraysType*)scan;
}
int main(void)
{
int hi[9053];
FILE *in_file;
in_file = fopen("message.txt", "r");
letsReturnArraysType arrayStruct = scanCode();
printf("%s", arrayStruct.return_value[0]);
printf("%s", arrayStruct.return_value[1]);
printf("%s", arrayStruct.return_value[2]);
printf("%s", arrayStruct.return_value[3]);
}

C program to extract different substrings from array of strings

I want to extract different substrings from a file with array of strings. My file resembles this.
abcdxxx
efghijkyyy
lmzzz
ncdslanclsppp
kdfmsqqq
cbskdnsrrr
From the above file I want to extract xxx, yyy, zzz, ppp, qqq, rrr (basically last 3 characters) and store into an array. I refered this link How to extract a substring from a string in C? but not felt feasible because the content in my file is dynamic and might change for next execution. Can someone give a brief on this?
Here is my approach
FILE* fp1 = fopen("test.txt","r");
if(fp1 == NULL)
{
printf("Failed to open file\n");
return 1;
}
char array[100];
while(fscanf(fp1,"%[^\n]",array)!=NULL);
for(i=1;i<=6;i++)
{
array[i] += 4;
}
the content in my file is dynamic and might change for next execution
Then you need realloc or a linked list:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
FILE *f;
char **arr = NULL;
char s[100];
size_t i, n = 0;
f = fopen("text.txt", "r");
if (f == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
while (fgets(s, sizeof s, f) != NULL) {
arr = realloc(arr, sizeof(*arr) * (n + 1));
arr[n] = calloc(4, 1);
memcpy(arr[n++], s + strlen(s) - 4, 3);
}
fclose(f);
for (i = 0; i < n; i++) {
printf("%s\n", arr[i]);
free(arr[i]);
}
free(arr);
return 0;
}
Output:
xxx
yyy
zzz
ppp
qqq
rrr
If you always want the last 3 characters you can simplify:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
FILE *f;
char (*arr)[4] = NULL;
char s[100];
size_t i, n = 0;
f = fopen("text.txt", "r");
if (f == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
while (fgets(s, sizeof s, f) != NULL) {
arr = realloc(arr, sizeof(*arr) * (n + 1));
memcpy(arr[n], s + strlen(s) - 4, 3);
arr[n++][3] = '\0';
}
fclose(f);
for (i = 0; i < n; i++) {
printf("%s\n", arr[i]);
}
free(arr);
return 0;
}

Unexpected Segfault - What am I doing wrong

I've been trying to blow the cobwebs off my C programming skills, and I've been getting an error I can't seem to figure out. This program reads in a list of integers separated by newlines. This bit happens in read_integer_file... I have no issues going through the input there. It's when I pass the data back to main via out that I have the problem.
#include <stdlib.h>
#include <stdio.h>
int read_integer_file(char* filename, int* out)
{
FILE* file;
file = fopen(filename, "r");
/* check if the file open was successful */
if(file == NULL)
{
return 0;
}
int num_lines = 0;
/* first check how many lines there are in the file */
while(!feof(file))
{
fscanf(file, "%i\n");
num_lines++;
}
/* seek to the beginning of the file*/
rewind(file);
out = malloc(sizeof(int)*num_lines);
if(out == NULL)
return 0;
int inp = 0;
int i = 0;
while(!feof(file))
{
fscanf(file, "%i\n", &inp);
out[i] = inp;
printf("%i\n", out[i]); /* <---- Prints fine here! */
i++;
}
return num_lines;
}
int main(int argc, char** argv)
{
if(argc < 2)
{
printf("Not enough arguments!");
return -1;
}
/* get the input filename from the command line */
char* array_filename = argv[1];
int* numbers = NULL;
int number_count = read_integer_file(array_filename, numbers);
for(int i = 0; i < number_count; i++)
{
/* Segfault HERE */
printf("%i\n", numbers[i]);
}
}
You have not allocated any memory for numbers. Currently it is pointing to no where. When it gets back to the calling function it is still pointed to nowhere. Pass a pointer to a pointer to the function to allocate it within the function.
int read_integer_file(char* filename, int** out)
{
...
*out = malloc(sizeof(int)*num_lines);
...
int number_count = read_integer_file(array_filename, &numbers);
This is a version of your code working.. Keep in mind also that fscanf just skip the \n the way you wrote it so it's like writing fscanf(file, "%d");
And if you don't put a variable to handle what it reads the compiler may not see it but you'll probably get an error..
So here is the code :
#include <stdlib.h>
#include <stdio.h>
int read_integer_file(char* filename, int **out)
{
FILE* file;
file = fopen(filename, "r");
/* check if the file open was successful */
if(file == NULL)
{
return 0;
}
int num_lines = 0;
int garbi;
char garbc;
/* first check how many lines there are in the file */
while(!feof(file))
{
fscanf(file, "%d", &garbi);
fscanf(file, "%c", &garbc);
if (garbc=='\n') ++num_lines;
}
/* seek to the beginning of the file*/
rewind(file);
int *nbr = malloc(sizeof(int)*num_lines);
if(nbr == NULL)
return 0;
int i = 0;
while(!feof(file))
{
fscanf(file, "%d", &nbr[i++]);
fscanf(file, "%c", &garbc);
}
*out=nbr;
return num_lines;
}
int main(int argc, char** argv)
{
if(argc < 2)
{
printf("Not enough arguments!");
return -1;
}
/* get the input filename from the command line */
char* array_filename = argv[1];
int *numbers = NULL;
int number_count = read_integer_file(array_filename, &numbers);
int i;
for(i = 0; i < number_count; ++i)
printf("%d\n", numbers[i]);
return 0;
}

Resources