I am creating a program that needs to read in an arbitrary amount of lines of arbitrary length each (but for now assuming one string per line). So basically, I need a dynamic array of dynamic string. I figured the easiest way to do this would be with a char double pointer. But I am getting errors with the asprintf statement. particularly "strings[track]". I figured this would point to the first char array. Any help on how to do this?
Here is the code so far:
char **strings;
int readFile(char* filename)
{
FILE *fp;
fp = fopen(filename, "r");
if (fp == NULL)
{
return -1;
}
char *singleLine = NULL;
ssize_t lineSize;
size_t amount = 0;
int track = -1;
while((lineSize = getline(&singleLine, &amount, fp)) != -1)
{
track++;
asprintf(&strings[track],"%s",singleline));
}
}
Related
I'm learning how to program C and I'm working on a project that requires code to read a value from a file and compare it to a INT value given by the user. To handle this I use this code
int id;
static const char filename[] = "ids.txt";
FILE *file = fopen(filename, "r");
int count = 0;
char line[255];
char line2[255];
if ( file != NULL )
{
char line[256];
while (fgets(line, sizeof line, file) != NULL) /* read a line */
{
if (id == *line)//PROBLEM IS ON THIS LINE
{
//the rest of my code
}
}
}
The code runs fine with no errors and when the value of line (the data read) and the value of id (the value given) they are both the same yet the program dose not seem to realize this. The problem occurs with this line of code if (id == *line) I'm assuming it has something to do with the data types of the variables but I cant seem to find a fix. Thank you for any help.
Thanks #WeatherVane for an answer to my problem. I use strtol() to fix my problem the code now looks like this
int id;
static const char filename[] = "ids.txt";
FILE *file = fopen(filename, "r");
int count = 0;
char line[255];
char *ptr;
long ret;
if ( file != NULL )
{
char line[256];
while (fgets(line, sizeof line, file) != NULL)
{
ret = strtol(line, &ptr, 10);
if (id == ret)
{
//rest of my code
}
}
}
int main(int argc, char *argv)
{
char filename[20]={};
int count=0;
if(argc==2)
{
strcpy(filename, argv[1]);
}
else
{
printf("Need 2 command line parameters\n");
}
FILE *fp=fopen(argv[1], "r");
while(fgets(filename, 20, fp))
{
count++;
}
fseek(fp, 0, SEEK_SET);
int ptr=(int)malloc(count*sizeof(int));
while(fgets(filename, 20, fp))
{
ptr[i]=
}
return 0;
for example,
my numbers in file are
19293
18239
19405
29302
10492
in each line, and I would like to put each line in an array.
How do I do this? It doesn't have to be in a while loop.
I think your question is that you want to store the content you read as a string each line.Ok, there are serveal methods to realize it.
If you don't care the effenciency, you can define a char pointer array as max as possible to contain all lines in your files. And you can do like this:
char* content[MAX_LINE] = { NULL };
char tmp[20];
char* ptr;
int i=0;
size_t ret;
FILE* fp;
fopen_s(&fp,"1.txt", "r");
while (fgets(tmp, 20, fp) != NULL)
{
ret = strlen(tmp);
ptr = (char*)malloc(ret+1);
strcpy_s(ptr, ret+1, tmp);
content[i++] = ptr;
}
And the better way is using pointer list.
If you want to read and store the whole content of your file in an array, you can do this in this simple way, though there are also other ways:
while( ( c = getc(file) ) != EOF )
buffer[i++] = c;
where buffer is an char array of 1000 elements(it could be any number, you want), c is a char, and i is an int initialized with 0.
I have an array of words:
const char *words[3]={cat,dog,snake,bee};
and a txt file like this one:
apple tree day night story bee oil lemons get fight 234 meow woof safari
jazz stuff what is dog fight street snake garden glass house bee question
foot head 29191 43493 ==
(where we don't know how many lines this file has)
I want to check the whole file and each time I find one of the words of the array to print that word and also print the line where it was found.
I'm having trouble with the comparison. My thought was to save every word of the file into an array and compare each one with the words of the words array. But i cannot do that. I have this:
FILE *f;
const char *arr;
f=fopen("test.txt","r");
while(fscanf(f,"%s",arr)!EOF)
I don't really know what to write here so that that I separate the file into words.
Please be kind to me, I'm only trying to learn.
There are several problems in the code snippets you've provided:
const char *words[3]={cat,dog,snake,bee};
Here you declare an array of 3 elements but you have 4 initializers. And you forgot to put the words between quotes.
Here you use fscanf to read into arr, but you didn't allocate memory, arr is not initialized, you probably meant to write char arr[200], 200 being the maximum word length.
FILE *f;
const char *arr;
f=fopen("test.txt","r");
while(fscanf(f,"%s",arr)!EOF)
You want this as base, tough there is still room form improvement:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char *words[] = { "cat", "dog", "snake", "bee" };
int main()
{
char line[200]; // maximum line size is 200
size_t len = 0;
FILE *f;
f = fopen("test.txt", "r");
if (f == NULL)
{
printf("Can't open file\n");
return 1;
}
int line_no = 0;
while (fgets(line, sizeof line, f))
{
++line_no;
// (sizeof words)/sizeof *words is the the number of words in the words array
for (int i = 0; i < (sizeof words)/sizeof *words; i++)
{
if (strstr(line, words[i]) != NULL)
{
printf("found %s in line %d\n", words[i], line_no);
}
}
}
fclose(f);
}
You are using fscanf() to read the words out of your file, which is not the best way to do this. You should use getline(3) or fgets(3) to read each line of your file.
Additionally, this line:
const char *words[3]={cat,dog,snake,bee};
Needs to be able to hold 4 char* pointers, not 3. You will also need to include quotes with these string literals. This is another way to do this:
const char *words[] = {"cat", "dog", "snake", "bee"};
Then to get the size of this array, just use sizeof(x) / sizeof(x[0]).
Furthermore, in this code segment:
FILE *f;
const char *arr;
f=fopen("test.txt","r");
while(fscanf(f,"%s",arr)!EOF)
You are using fscanf() on an uninitialized pointer, which leads to many problems. If you wish to use a pointer, you may need to dynamically allocate arr on the heap with malloc(3). If you don't wish to do this, just declare a VLA, such as char arr[200]. Also fscanf() returns number of items scanned, so fscanf(f,"%s",arr)!=EOF will have to be replaced with fscanf(f,"%s",arr)==1, to ensure one word is being read at a time.
Note: You should also check if FILE *f was opened correctly, as it can return NULL on error.
I'm having trouble with the comparison. My thought was to save every word of the file into an array and compare each one with the words of the words array.
As others have mentioned to use strstr(3), another possible option is to use strtok(3) to parse each word on the line, then use strcmp(3) to compare words[i] with the word parsed from the file. If words[] becomes bigger in the future, I would suggest using binary search instead of linear search to compare the words. This will improve you search time from O(n) to O(logn).
Here is some (modified) code I wrote before which does something similar:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARRAYSIZE(x) (sizeof x / sizeof x[0])
int main(void) {
const char *words[] = {"cat", "dog", "snake", "bee"};
FILE *fptr;
char *line = NULL, *word = NULL;
const char *delim = " \n";
size_t len = 0, lineno = 0;
ssize_t read;
fptr = fopen("somewords.txt", "r");
if (fptr == NULL) {
fprintf(stderr, "Error reading file\n");
exit(EXIT_FAILURE);
}
while ((read = getline(&line, &len, fptr)) != -1) {
lineno++;
word = strtok(line, delim);
while (word != NULL) {
for (size_t i = 0; i < ARRAYSIZE(words); i++) {
if (strcmp(word, words[i]) == 0) {
printf("Found matched word: %s, Line number: %zu\n", word, lineno);
}
}
word = strtok(NULL, delim);
}
}
free(line);
fclose(fptr);
return 0;
}
Use getline & strstr
char *line = NULL;
size_t len = 0;
ssize_t read;
int line_no = 0;
while ((read = getline(&line, &len, f)) != -1)
{
++line_no;
for (int i = 0; i < 3; i++) {
if (strstr(line, words[i]) != null)
{
// if matched
}
}
}
My input file contains the following :
w 7b034d90
r 7b034c68
r df84d4
How do I read and store the first character into a variable and the second in another variable ? This has to be done for several lines of input.
For e.g I need to store w into variable A and 7b034d90 into variable B . This has to be done for several thousand lines and the first character of each line will be either w or r. What is the best way of going about this ?
Here is my code :
struct MemBlock
{
char address
char ReadorWrite;
};
struct MemBlock blocks[100]
int main (int argc, char *argv[])
{
int line = 0;
static const char filename[] = "sampleTest.txt";
FILE *file = fopen ( filename, "r" );
if (fp == NULL)
{
printf ("Error opening the file\n\n'");
exit(EXIT_FAILURE);
} else {
if (argc == 3)
{
for (i=0,i<100,i++)
{
while ( fgets ( line, sizeof line, file ) != NULL )
{
r = fscanf(fp, "%s %s\n", blocks[i].ReadOrWrite, blocks[i].address);
line++;
}
}
fclose(fp);
}
}
If you don't know how many pairs of you have, you will need to keep track of them via some mechanism. One would be to malloc and link them into a list. In order to do this, add a pointer to the struct.
So the flow would be something like the pseudo-code below. It will need the struct definition, error code, the API file calls to be correct, and make sure that the linked list is correct.
struct Memblock head;
struct Memblock *oldp = &head;
main() {
fp = fopen(file);
while (fgets(line, fp, sizeof(line)-1) != NULL) {
if (sscanf(line, "%c %d", &flag, &address) == 2) {
sp = malloc(sizeof(struct));
sp->flag = flag;
sp->address = address;
sp->next = NULL;
oldp->next = sp;
}
}
}
Lets assume OP wants an array of struct MemBlock when done
C pseudo code (error handling omitted)
struct MemBlock {
unsigned long address; // Data is obviously hexadecimal
char ReadorWrite;
};
FILE *inf = fopen(filename, "rt"); // Use "rt"
size_t line = 0;
char buffer[1+1+16+2+100]; // big enough for expected letter and number + change
while (fgets(buf, sizeof buf, inf) != NULL) line++;
frewind(inf);
struct MemBlock *Array = calloc(line, sizeof *Array);
for (size_t i = 0; i< line; i++) {
if (fgets(buf, sizeof buf, inf) != NULL)) handle error
if (2 !=sscanf("%c%lx", &Array[i].ReadorWrite, &Array[i].address)) handle error
}
fclose(inf);
// Use Array[] with length `line`.
...
free(Array)
I like the one-pass link list idea, but wanted to offer another POV.
There are two many method like sscanf() or use strchr() or in c++, something like http://www.boost.org/doc/libs/1_54_0/libs/filesystem/example/tut3.cpp
I'm writing a BF interpreter in C and I've run into a problem reading files. I used to use scanf in order to read the first string, but then you couldn't have spaces or comments in your BF code.
Right now here is what I have.
char *readFile(char *fileName)
{
FILE *file;
char *code = malloc(1000 * sizeof(char));
file = fopen(fileName, "r");
do
{
*code++ = (char)fgetc(file);
} while(*code != EOF);
return code;
}
I know the problem arises in how I'm assigning the next char in the file to the code pointer but I'm just not sure what that is.
My pointer knowledge is lacking which is the point of this exercise.
The interpreter works fine, all using pointers, I'm just having a problem reading files in to it.
(I'm going to implement only reading +-><[]., into the file later, although if anyone has a good way to do it, it would be great if you'd let me know!)
There are a number of things wrong with your code:
char *readFile(char *fileName)
{
FILE *file;
char *code = malloc(1000 * sizeof(char));
file = fopen(fileName, "r");
do
{
*code++ = (char)fgetc(file);
} while(*code != EOF);
return code;
}
What if the file is greater than 1,000 bytes?
You are increasing code each time you read a character, and you return code back to the caller (even though it is no longer pointing at the first byte of the memory block as it was returned by malloc).
You are casting the result of fgetc(file) to char. You need to check for EOF before casting the result to char.
It is important to maintain the original pointer returned by malloc so that you can free it later. If we disregard the file size, we can achieve this still with the following:
char *readFile(char *fileName)
{
FILE *file = fopen(fileName, "r");
char *code;
size_t n = 0;
int c;
if (file == NULL)
return NULL; //could not open file
code = malloc(1000);
while ((c = fgetc(file)) != EOF)
{
code[n++] = (char) c;
}
// don't forget to terminate with the null character
code[n] = '\0';
return code;
}
There are various system calls that will give you the size of a file; a common one is stat.
Expanding upon the above code from #dreamlax
char *readFile(char *fileName) {
FILE *file = fopen(fileName, "r");
char *code;
size_t n = 0;
int c;
if (file == NULL) return NULL; //could not open file
fseek(file, 0, SEEK_END);
long f_size = ftell(file);
fseek(file, 0, SEEK_SET);
code = malloc(f_size);
while ((c = fgetc(file)) != EOF) {
code[n++] = (char)c;
}
code[n] = '\0';
return code;
}
This gives you the length of the file, then proceeds to read it character by character.
Here's one simple way to ignore everything but valid brainfuck characters:
#define BF_VALID "+-><[].,"
if (strchr(BF_VALID, c))
code[n++] = c;
the file is being opened and not closed for each call to the function also
I think the most significant problem is that you're incrementing code as you read stuff in, and then returning the final value of code, i.e. you'll be returning a pointer to the end of the string. You probably want to make a copy of code before the loop, and return that instead.
Also, C strings need to be null-terminated. You need to make sure that you place a '\0' directly after the final character that you read in.
Note: You could just use fgets() to get the entire line in one hit.
Either of the two should do the trick -
char *readFile(char *fileName)
{
FILE *file;
char *code = malloc(1000 * sizeof(char));
char *p = code;
file = fopen(fileName, "r");
do
{
*p++ = (char)fgetc(file);
} while(*p != EOF);
*p = '\0';
return code;
}
char *readFile(char *fileName)
{
FILE *file;
int i = 0;
char *code = malloc(1000 * sizeof(char));
file = fopen(fileName, "r");
do
{
code[i++] = (char)fgetc(file);
} while(code[i-1] != EOF);
code[i] = '\0'
return code;
}
Like the other posters have pointed out, you need to ensure that the file size does not exceed 1000 characters. Also, remember to free the memory when you're done using it.
The problem here is twofold
a) you increment the pointer before you check the value read in, and
b) you ignore the fact that fgetc() returns an int instead of a char.
The first is easily fixed:
char *orig = code; // the beginning of the array
// ...
do {
*code = fgetc(file);
} while(*code++ != EOF);
*code = '\0'; // nul-terminate the string
return orig; // don't return a pointer to the end
The second problem is more subtle -fgetc returns an int so that the EOF value can be distinguished from any possible char value. Fixing this uses a temporary int for the EOF check and probably a regular while loop instead of do / while.