How to read lines from file into an array of strings? - c

#define LINES 4
#define LENGHT 30
typedef struct
{
char *name;
char *phoneNumber;
char *location;
char *traveltype;
} Client;
int main(int argc, char *argv[])
{
char *filename = argv[1];
char clientData[LINES][LENGHT];
readClientData(filename, clientData);
/* How to do this client struct */
Client *client = createClient(clientData[0], clientData[1], clientData[2], clientData[3]);
return 0;
}
void readClientData(char *filename, char clientData[LINES][LENGHT])
{
FILE *file = fopen(filename, "r");
if (file == NULL)
{
perror("Error while opening file!");
exit(1);
}
char line[LENGHT];
int i = 0;
while (fgets(line, LENGHT, file) != NULL)
clientData[i] = line; /* How to do this */
i++;
fclose(file);
}
Coming from a pythonista world I'm a bit confused how things are working here. It is clear that I can't just add lines to the list, nor can acces the lines the way I do to initialize the client struct.
Maybe I should just use a char *clientData[], but don't know how.

To copy C strings, you need to use:
char * strcpy ( char * destination, const char * source );
from the Standard C String Library, string.h.
However, notice, than unlike Python (your background), indentation does not define the body of the loop, you need to use curly brackets!
So, you need to do this:
while (fgets(line, LENGHT, file) != NULL)
{
strcpy(clientData[i], line);
i++;
}
Without the curly brackets, only the first immediate line of code will be considered to be the body of the loop. So, in the example above, the body of the loop - if we did not use curly brackets - would be only the call to the method for copying strings, and the increment of the counter would not be part of the loop!
You need to define, or just declare a method before using it, which you didn't do in your example.
Since you only need one client, you do not need a pointer, you can simply create one, by doing Client client;.
In order to keep it simple, use the knowledge you gathered from reading this answer so far, and do define the maximum length of the strings (that is the size of the arrays of characters every field of your struct gets to have). Remember, that C strings have to be NULL terminated, so, the maximum length of them is actually LENGTH - 1.
If you keep the fields of the struct as pointers to char, then you'd need to dynamically allocate memory, or set the pointer point to corresponding string of the clientData array (similarly to what you did for the file name). I suggest you get some experience in C first, and then try implementing these two approaches.
Now, you are ready to do:
strcpy(client.name, clientData[0]);
...
strcpy(client.traveltype, clientData[3]);
Complete working example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define LINES 4
#define LENGTH 30
typedef struct
{
char name[LENGTH];
char phoneNumber[LENGTH];
char location[LENGTH];
char traveltype[LENGTH];
} Client;
void readClientData(char *filename, char clientData[LINES][LENGTH]);
void printClient(Client client);
int main(int argc, char *argv[])
{
char *filename = NULL;
if(argc > 1)
filename = argv[1];
else
{
printf("Usage: %s <filename>\n", argv[0]);
}
char clientData[LINES][LENGTH];
readClientData(filename, clientData);
Client client;
strcpy(client.name, clientData[0]);
strcpy(client.phoneNumber, clientData[1]);
strcpy(client.location, clientData[2]);
strcpy(client.traveltype, clientData[3]);
printClient(client);
return 0;
}
void readClientData(char *filename, char clientData[LINES][LENGTH])
{
FILE *file = fopen(filename, "r");
if (file == NULL)
{
perror("Error while opening file!");
exit(1);
}
char line[LENGTH];
int i = 0;
while (fgets(line, LENGTH, file) != NULL)
{
line[strcspn(line, "\n")] = 0;
strcpy(clientData[i], line);
i++;
}
fclose(file);
}
void printClient(Client client)
{
printf("%s, %s, %s, %s\n", client.name, client.phoneNumber, client.location, client.traveltype);
}
Output:
Georgioss-MBP:Desktop gsamaras$ cat test.txt
MegasAlexandros
3335632320
Greece
Cosmos
Georgioss-MBP:Desktop gsamaras$ gcc main.c
Georgioss-MBP:Desktop gsamaras$ ./a.out test.txt
MegasAlexandros, 3335632320, Greece, Cosmos
PS: I used this in my example: Removing trailing newline character from fgets() input

Related

How to print a substring in C

simple C question here!
So I am trying to parse through a string lets say: 1234567W
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
//pointer to open file
FILE *op;
//open file of first parameter and read it "r"
op = fopen("TestCases.txt", "r");
//make an array of 1000
char x[1000];
char y[1000];
//declare variable nums as integer
int nums;
//if file is not found then exit and give error
if (!op) {
perror("Failed to open file!\n");
exit(1);
}
else {
while (fgets(x, sizeof(x), op)) {
//pounter to get the first coordinate to W
char *p = strtok(x, "W");
//print the first 3 digits of the string
printf("%.4sd\n", p);
}
}
return 0;
My output so far shows: "123d" because of the "%.4sd" in the printf function.
I now need to get the next two numbers, "45". Is there a regex expression I can use that will allow me to get the next two digits of a string?
I am new to C, so I was thinking more like "%(ignore the first 4 characters)(print next 2 digits)(ignore the last two digits)"
input: pic
output: pic
Please let me know.
Thanks all.
printf("Next two: %.2s\n", p + 4); should work.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
//pointer to open file
FILE *op;
//open file of first parameter and read it "r"
op = fopen("TestCases.txt", "r");
//make an array of 1000
char x[1000];
char y[1000];
//declare variable nums as integer
int nums;
//if file is not found then exit and give error
if (!op) {
perror("Failed to open file!\n");
exit(1);
}
else {
while (fgets(x, sizeof(x), op)) {
//pounter to get the first coordinate to W
char *p = strtok(x, "W");
//print the first 3 digits of the string
printf("%.4sd\n", p);
printf("Next two: %.2s\n", p + 4);
}
}
return 0;
}
Side note: I added a missing stdio.h include. Please turn on compiler warnings, since this error would've been caught by them.

Get the user to enter a name but using file stream *fp

I am a beginner in c so I have a problem with get the user to input last name, a comma & then first name. However it will pass to the function call
int get_name(FILE *fp)
in my main function. I have a problem either if I have to use the arguments parameters.
Example, main (int argc, char *argv[])) or just main (void))
and from what I have been searching so far, FILE*fp cannot get the user to enter from stdin it only use to open the file(?) BUT I am required to get the user to input from keyboard and pass to the function. I have written some codes. but they don't seem to work but I am going to put down on here the one I am sure that I need a few changes most.
#define LINESIZE1024
int main(void){
FILE *fp;
char line[LINESIZE];
char first;
char last;
char comma;
while(1){
if(!fgets(line,LINESIZE,stdin)){
clearerr(stdin);
break;
}
if(fp = (sscanf(line,"%s %s %s",&last,&comma,&first)==3))
get_name(fp);
if(get_last_first(fp)== -1)
break;
printf("Please enter first name a comma and then last name");
}
BUT I got an error saying I can't use pass it from pointer to an integer. and many MORE but I accidentally closed my concolse and all the errors that appeared while I was trying to fix are gone. So please give me some ideas.
What about seconde code
while(1){
if(!fgets(line,LINESIZE,fp)){
clearerr(stdin);
break;
}
if(sscanf(line,"%s %s %s",last,comma,first)==3)
get_last_first(fp);
return 0;
}
It gave me errors too. fp,last,first,comma used uninitialized in this function
OK so I think I have fixed the previous problem now. However it doesn't print the name back if the name is given correctly. Here is my fixed main code.
int main(void){
FILE *fp = stdin;
char line[LINESIZE];
char first[16];
char last[16];
while(1){
if(!fgets(line,LINESIZE,stdin)){
clearerr(stdin);
break;
}
if(sscanf(line,"%s ,%s",last,first)==2)
if(get_name(fp)==2)
printf("Your name is: %s %s\n", first, last);
}
return 0;
}
here is my function.
int get_name(FILE *fp){
char line[LINESIZE];
char last[16], first[16];
int n;
/* returns -1 if the input is not in the correct format
or the name is not valid */
if(fgets(line, LINESIZE, fp) == NULL) {
return -1;
}
/* returns 0 on EOF */
if((n = sscanf(line, " %[a-zA-Z-] , %[a-zA-Z-]", last, first)) == EOF) {
return 0;
}
/* prints the name if it's valid */
if((n = sscanf(line, " %[a-zA-Z-] , %[a-zA-Z-]", last, first)) == 2) {
return 2;
}
return 1;
}
I thank you people so much for taking time to read and help me. Please don't be mean :)
Seems that you are making it more complicated than needed. Don't call fgets and scanf in main. Only do that in the function get_name.
It can be something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINESIZE 1024
int get_name(FILE *fp)
{
char line[LINESIZE];
char* t;
if(!fgets(line, LINESIZE,fp))
{
printf("Error reading input\n");
return 0;
}
t = strstr(line, ",");
if (t)
{
*t = '\0';
++t;
printf("First: %s - Last: %s\n", line, t);
return 2;
}
printf("Illegal input\n");
return 0;
}
int main(int argc, char **argv)
{
get_name(stdin);
return 0;
}
If you later decide that you want to read from a file, you can reuse the function get_name without changing it at all. All you need is to change main. Like:
int main(int argc, char **argv)
{
FILE* f = fopen("test.txt", "r");
if (f)
{
get_name(f);
fclose(f);
}
else
{
printf("Open file failed\n");
}
return 0;
}
If you want to read from the keyboard, read from stdin or use scanf, which internally reads from stdin. If you want to read from a file instead, use FILE *fp, but don't forget to open the file and check if it was successful (you'll find lots of tutorials for this).
Further, when reading in strings, you need an array of characters, not a single one. Note further, that scanf can already deal with formats like "everything that is not a ',' then a ',' then a string. Note that format "[^,]" means "any character except a ',':
So you could adapt the code as follows:
#define LINESIZE 1024
int main(void){
char line[LINESIZE];
char first[LINESIZE];
char last[LINESIZE];
while(fgets(line,LINESIZE,stdin)) {
if(sscanf(line,"%[^,],%s",last,first)==2) {
printf("Read in %s ... %s\n",last,first);
}
else {
printf("Please enter first name a comma and then last name");
}
}
return 0;
}
And if your professor is picky concerning the "use FILE*", you could write:
FILE *fp = stdin;
...
while(fgets(line,LINESIZE,fp)) {
...

Storing line by line from text file into char array using char pointer

Hello I writing a program to execute commands from the text file. The code below is used to store line by line into char array first.
So I expect it to do something like
args[0]= The first line of text file
args[1]= The second line of text file
... and so on
In my code, all of the arrays would be covered by the last array. And I can't figure out why.
Can anyone help me fix this and tell me why my code does that. Also I need to keep char *args[]. cos I would use it with execvp() later.
int main(int argc, const char * av[]) {
FILE *fp;
fp = fopen(av[1],"r");
int n_lines=0;
char in[100],*args[16];
int size=sizeof(in);
while(fgets(in, size, fp)!=NULL){
args[n_lines] = in;
printf("Args[0] is %s\n",args[0]);
n_lines++;
}
printf("Now Args[0] is %s\n",args[0]);
}
Output
zacks-MacBook-Pro:prac2 zack$ ./a.out test
Args[0] is ./addone
Args[0] is ./add
Now Args[0] is ./add
int n_lines=0;
char in[100],*args[16];
int size=sizeof(in);
while(fgets(in, size, fp)!=NULL){
args[n_lines] = in;
printf("Args[0] is %s\n",args[0]);
n_lines++;
}
The value of in is overwritten on each iteration, you need to reserve space (using malloc->strcpy or strdup if available):
char in[100], *args[16];
while (fgets(in, sizeof in, fp) != NULL) {
args[n_lines] = strdup(in);
...
n_lines++;
}
Or use a 2D array (an adjust of sizeof is required in fgets):
char in[16][100];
while (fgets(in[n_lines], sizeof in[0], fp) != NULL) {
...
n_lines++;
}
And as pointed out by #MichaelWalz in comments: you'll run into problems if your file has more then 16 lines.
Change to
while (fgets(in[n_lines], sizeof in[0], fp) != NULL) {
...
if (++n_lines == (sizeof in / sizeof in[0])) break;
}

How to read in txt file in CSV format and save into array in C

I am new to C and I need to read in a .txt file where there are 3 fields in each line separated by a comma, and I need to save it into an array. I am wondering how to do this?
Here is an example file:
0, "test", 100
1, "hi", 2
2, "goodbye", 0
So I am wondering how to read the file line by line and to store each element into an array. I have started by defining a struct:
typedef struct data {
int col1;
char *col2;
int col3;
} data_t;
Could anyone help me out to get started with the file opening?
The SQLite shell has an .import command that reads CSV. It is worthy of study. You can find it here; search for CSVReader to see how it's coded.
For file opening there is a standard library (include stdio.h) function named fopen. It has the following declaration:
FILE *fopen(const char *filename, const char *mode);
As you can see it expects you to provide a pointer to const char for both filename and mode (read/write/read+write). It will return a pointer to a FILE so inside the function where you intend to work with it you'd have to declare one like this:
FILE *my_file;
It's also a good idea to initialize it to NULL so that you can check for errors when using fopen.
In your main function (purely for reading):
FILE *my_file = NULL;
my_file = fopen("filename.txt", "r");
And check for the returned pointer:
if (my_file == NULL)
//error message etc.
simply sample(check omit)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUMOFDATA 10
typedef struct data {
int col1;
char *col2;
int col3;
} data_t;
int main(){
data_t data_array[NUMOFDATA];
int data_count = 0;
char line[128];
FILE *fp;
fp=fopen("data.txt", "r");
while(fgets(line, sizeof(line), fp)){
int col1, col3;
char col2[64];
if(sscanf(line, "%d, %63[^,], %d", &col1, col2, &col3)==3){
char *cl2p = col2;
data_array[data_count].col1 = col1;
data_array[data_count].col3 = col3;
if(col2[0] == '"'){
char *p = strchr(&col2[1], '"');
if(p)
*p = '\0';
cl2p = &col2[1];
}
data_array[data_count].col2 = strdup(cl2p);
//printf("%d, \"%s\", %d\n",data_array[data_count].col1,data_array[data_count].col2,data_array[data_count].col3);
if(++data_count == NUMOFDATA)break;
}
}
fclose(fp);
return 0;
}

reading first line of a file in c

I am very new to C and I am having trouble with the most fundamental ideas in C. We are starting structures and basically the assignment we are working on is to read a delimited file and save the contents into a structure. The first line of the file has the number of entries and alls that I am trying to do at the moment is get the program to read and save that number and print it out. Please do not assume I know anything about C I really am very new to this.
This code is giving me a segmentation fault
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct info{
char name[100];
char number[12];
char address[100];
char city[20];
char state[2];
int zip;
};
int strucCount;
char fileText[1];
int main(char *file)
{
FILE *fileStream = fopen(file, "r");
fgets(fileText, 1, fileStream);
printf("\n%s\n",fileText);
fclose(fileStream);
}
Here is the sample file
4
mike|203-376-5555|7 Melba Ave|Milford|CT|06461
jake|203-555-5555|8 Melba Ave|Hartford|CT|65484
snake|203-555-5555|9 Melba Ave|Stamford|CT|06465
liquid|203-777-5555|2 Melba Ave|Barftown|CT|32154
Thanks for everyones comments, they helped a lot, sorry to Jim. I am working on very little sleep and didn't mean to offend anyone, I am sure we have all been there haha.
SUGGESTION:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXLINE 80
#define MAXRECORDS 10
struct info{
char name[100];
char number[12];
char address[100];
char city[20];
char state[2];
int zip;
};
int
main(int argc, char *argv[])
{
FILE *fp = NULL;
int nrecs = 0;
char line[MAXLINE];
struct info input_records[MAXRECORDS];
/* Check for cmd arguments */
if (argc != 2) {
printf ("ERROR: you must specify file name!\n");
return 1;
/* Open file */
fp = fopen(argv[1], "r");
if (!fp) {
perror ("File open error!\n");
return 1;
}
/* Read file and parse text into your data records */
while (!feof (fp)) {
if (fgets(line, sizeof (line), fp) {
printf("next line= %s\n", line);
parse(line, input_records[nrecs]);
nrecs++;
}
}
/* Done */
fclose (fp);
return 0;
}
fclose(fileStream);
}
Key points:
Note use of "argc/argv[]" to read input filename from command line
line, nrecs, etc are all local variables (not globals)
Check for error conditions like "filename not given" or "unable to open file"
Read your data in a loop, until end of input file
Parse the data you've read from the text file into an array of binary records (TBD)

Resources