when we download some same files on Internet, the filename becomes (2), (3)...
example
I want to remove these files with C. First of all, I want to find files and print.
I write some code blow. But It doesn't work.
int main(){
const char *path;
DIR *dir;
struct dirent* entry;
if((path=getenv("HOME"))==NULL){//get HOME path
path = getpwuid(getuid())->pw_dir;
}
const char *downloads = "/Downloads";
strcat(path,downloads); //make ~/Downloads
if(chdir(path)!=0){
perror("chdir()");
return -1;
}
if((dir=opendir(path))==NULL){ //open directory
perror("open");
return 1;
}
while((entry=readdir(dir))!=NULL){
struct dirent *cmpentry;
DIR *cmpdir;
if((cmpdir=opendir(path))==NULL){
perror("opendir");
return -1;
}
while((cmpentry=readdir(cmpdir))!=NULL){
if((entry->d_name[0]!='.')&&strcmp(entry->d_name,cmpentry->d_name)!=0){
char *ptr=strstr(cmpentry->d_name,entry->d_name);
if(ptr!=NULL)
printf("%s\n",cmpentry->d_name);
}
}
}
}
How can i fix it?
A number of issues ...
path does not have enough space for the strcat, so you have UB (undefined behavior)
No need to use chdir
No closedir calls, so for a large directory, you'll run out of file descriptors.
No skip of . and .. entries
Using strcmp and strstr is not sufficient. Duplicates and/or misses.
Opening the same directory repeatedly is slow/wasteful. Better read the directory once and save the entries in an array.
Some fixes:
Capture the data in an array
Use an auxiliary struct (e.g. struct root below) that splits up the filenames into component parts (e.g. foo(1).pdf --> foo, (1), and .pdf)
Added comparison of lengths and file contents
Here is the original code, annotated with the bugs:
int
main()
{
const char *path;
DIR *dir;
struct dirent *entry;
// get HOME path
if ((path = getenv("HOME")) == NULL) {
path = getpwuid(getuid())->pw_dir;
}
const char *downloads = "/Downloads";
// make ~/Downloads
// NOTE/BUG: not enough space in path
// NOTE/BUG: path is a const
strcat(path, downloads);
// NOTE/BUG: no need to chdir as opendir is enough
if (chdir(path) != 0) {
perror("chdir()");
return -1;
}
// open directory
// NOTE/BUG: no closedir for this
if ((dir = opendir(path)) == NULL) {
perror("open");
return 1;
}
while ((entry = readdir(dir)) != NULL) {
// NOTE/BUG: no check for "." or ".."
struct dirent *cmpentry;
DIR *cmpdir;
// NOTE/BUG: no closedir for this
if ((cmpdir = opendir(path)) == NULL) {
perror("opendir");
return -1;
}
while ((cmpentry = readdir(cmpdir)) != NULL) {
// NOTE/BUG: strcmp sense is inverted
// NOTE/BUG: strcmp wrong
if ((entry->d_name[0] != '.') &&
strcmp(entry->d_name, cmpentry->d_name) != 0) {
char *ptr = strstr(cmpentry->d_name, entry->d_name);
if (ptr != NULL)
printf("%s\n", cmpentry->d_name);
}
}
}
}
In the above code, I've used cpp conditionals to denote old vs. new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Note: this can be cleaned up by running the file through unifdef -k
Here is the refactored code. It is annotated:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <pwd.h>
#include <string.h>
#include <dirent.h>
#include <ctype.h>
#include <sys/stat.h>
#ifdef DEBUG
#define dbgprt(_fmt...) \
fprintf(stderr,_fmt)
#else
#define dbgprt(_fmt...) \
do { } while (0)
#endif
// filename parsing control
struct root {
struct dirent root_ent; // raw directory entry
off_t root_size; // file size
int root_paren; // 1=has "(1)"
int root_dup; // 1=is a duplicate
char *root_suf; // suffix/entension (e.g. ".pdf")
char root_core[256]; // root/core/base name
};
// rootshow -- show root struct contents
void
rootshow(const struct root *root,const char *who)
{
dbgprt("rootshow: d_name='%s' root_dup=%d root_paren=%d root_core='%s' root_suf='%s' (from %s)\n",
root->root_ent.d_name,
root->root_dup,root->root_paren,
root->root_core,root->root_suf,who);
}
// rootof -- split up filenames into components
void
rootof(struct root *root,struct dirent *ent,off_t size)
{
char tail[256];
memset(root,0,sizeof(*root));
do {
// get directory entry
root->root_ent = *ent;
// remember the file size
root->root_size = size;
// get the filename
strcpy(tail,ent->d_name);
// remember and strip the extension
char *dot = strrchr(tail,'.');
if (dot != NULL) {
root->root_suf = &ent->d_name[dot - tail];
*dot = 0;
}
// get root/base (e.g. "foo.pdf" --> "foo")
strcpy(root->root_core,tail);
// rightmost part of file must be "(1)"
char *rparen = &tail[strlen(tail) - 1];
if (*rparen != ')')
break;
// assume it's of the correct form
root->root_paren = 1;
// look for "(" and ensure it has some digits
char *lparen = rparen - 1;
for (; lparen >= tail; --lparen) {
if (*lparen == '(')
break;
if (! isdigit(*lparen)) {
root->root_paren = 0;
break;
}
}
// we got something like "X)" (i.e. _not_ "(1)")
if (! root->root_paren)
break;
// assume it's _not_ a match
root->root_paren = 0;
// we got something like "()"
if ((lparen + 1) == rparen)
break;
// we must have the "("
if (lparen < tail)
break;
if (*lparen != '(')
break;
// strip "(1)"
*lparen = 0;
root->root_paren = 1;
strcpy(root->root_core,tail);
} while (0);
#if DEBUG
rootshow(root,"rootof");
#endif
}
// fullpath -- get full path (e.g. dir/tail)
void
fullpath(char *path,const char *dir,const char *tail)
{
strcpy(path,dir);
strcat(path,"/");
strcat(path,tail);
}
// dirload -- load up directory into list
struct root *
dirload(const char *path,int *countp)
{
char file[1024];
struct root *list = NULL;
int count = 0;
int cap = 0;
// open directory
DIR *dirp = opendir(path);
if (dirp == NULL) {
perror("open");
exit(1);
}
while (1) {
struct dirent *ent = readdir(dirp);
if (ent == NULL)
break;
// skip over "." and ".."
const char *tail = ent->d_name;
if (tail[0] == '.') {
if (tail[1] == 0)
continue;
if ((tail[1] == '.') && (tail[2] == 0))
continue;
}
// optional -- only ordinary files
#if 1
if (ent->d_type != DT_REG)
continue;
#endif
// enlarge array
if (count >= cap) {
cap += 10;
list = realloc(list,sizeof(*list) * cap);
if (list == NULL) {
perror("realloc");
exit(1);
}
}
// get file size
struct stat st;
fullpath(file,path,ent->d_name);
if (stat(file,&st) < 0) {
perror(file);
exit(1);
}
// parse the filename
rootof(&list[count],ent,st.st_size);
++count;
}
closedir(dirp);
// return count to caller
*countp = count;
return list;
}
// filematch -- compare the file contents
// RETURNS: 1=match, 0=mismatch
int
filematch(const char *dir,const struct root *lhs,const struct root *rhs)
{
int fdlhs;
char lhsfile[1024];
char lhsbuf[4096];
int fdrhs;
char rhsfile[1024];
char rhsbuf[4096];
int match = 0;
do {
// file sizes must match
if (lhs->root_size != rhs->root_size)
break;
// open the LHS file
fullpath(lhsfile,dir,lhs->root_ent.d_name);
fdlhs = open(lhsfile,O_RDONLY);
if (fdlhs < 0) {
perror(lhsfile);
exit(1);
}
// open the RHS file
fullpath(rhsfile,dir,rhs->root_ent.d_name);
fdrhs = open(rhsfile,O_RDONLY);
if (fdrhs < 0) {
perror(rhsfile);
exit(1);
}
match = 1;
off_t resid = lhs->root_size;
ssize_t rlen;
ssize_t xlen;
for (; resid > 0; resid -= rlen) {
if (resid > sizeof(lhsbuf))
rlen = sizeof(lhsbuf);
else
rlen = resid;
// get LHS chunk
xlen = read(fdlhs,lhsbuf,rlen);
if (xlen != rlen) {
perror(lhsfile);
exit(1);
}
// get RHS chunk
xlen = read(fdrhs,rhsbuf,rlen);
if (xlen != rlen) {
perror(rhsfile);
exit(1);
}
// they must match
if (memcmp(lhsbuf,rhsbuf,rlen) != 0) {
match = 0;
break;
}
}
close(fdlhs);
close(fdrhs);
} while (0);
return match;
}
int
main(int argc,char **argv)
{
char path[1024];
// skip over program name
--argc;
++argv;
// find the directory
do {
if (argc > 0) {
strcpy(path,*argv);
break;
}
// get HOME path
const char *home = getenv("HOME");
if (home == NULL)
home = getpwuid(getuid())->pw_dir;
// make ~/Downloads
fullpath(path,home,"Downloads");
} while (0);
#if DEBUG
setlinebuf(stdout);
setlinebuf(stderr);
#endif
int count = 0;
struct root *list = dirload(path,&count);
for (int lhsidx = 0; lhsidx < count; ++lhsidx) {
struct root *lhs = &list[lhsidx];
// must _not_ have "(1)"
if (lhs->root_paren)
continue;
rootshow(lhs,"LHS");
for (int rhsidx = 0; rhsidx < count; ++rhsidx) {
// skip over the same entry
if (rhsidx == lhsidx)
continue;
struct root *rhs = &list[rhsidx];
rootshow(rhs,"RHS");
// file types must match
if (rhs->root_ent.d_type != lhs->root_ent.d_type)
continue;
// must have "(1)"
if (! rhs->root_paren)
continue;
// suffix must match
// both entries must have [or _not_ have] a suffix
if (lhs->root_suf != NULL) {
if (rhs->root_suf == NULL)
continue;
if (strcmp(lhs->root_suf,rhs->root_suf) != 0)
continue;
}
else {
if (rhs->root_suf != NULL)
continue;
}
// core must match
if (strcmp(lhs->root_core,rhs->root_core) != 0)
continue;
// contents must match
if (! filematch(path,lhs,rhs))
continue;
printf("%s is dup of %s\n",
rhs->root_ent.d_name,lhs->root_ent.d_name);
// mark it as a removable duplicate
rhs->root_dup = 1;
}
}
return 0;
}
Here is a test perl script:
#!/usr/bin/perl
# dotest -- test program
master(#ARGV);
exit(0);
# master -- master control
sub master
{
my(#argv) = #_;
$xfile = shift(#argv);
$xfile //= "duptest";
$pwd = $ENV{PWD};
$xfile = "$pwd/$xfile";
$tstdir = "/tmp/testdir";
dotest("abc","xyz");
dotest("abc.pdf","jkl");
dotest("abc(1).pdf","jkl");
dotest("abc(2)","xyz");
dotest("abc(3)","xx");
dotest("abc(3)","xzy");
dotest("def","blah");
dotest("def(3)","blah");
dotest("def.pdf","blah");
}
sub dotest
{
my($file,$body) = #_;
printf("\n");
printf("%s\n","-" x 80);
system("rm -fr $tstdir");
system("mkdir -p $tstdir");
push(#allfiles,[$file,$body]);
####rfiles = shuffle(#allfiles);
#rfiles = #allfiles;
foreach $pair (#rfiles) {
($tail,$body) = #$pair;
printf("dotest: FILE %s '%s'\n",$tail,$body);
$file = sprintf("%s/%s",$tstdir,$tail);
open($xfdst,">$file") or
die("dotest: unable to open '$file' -- $!\n");
print($xfdst $body);
close($xfdst);
}
#fsort = sort(#allfiles);
#xfiles = (`$xfile $tstdir`);
$code = $? >> 8;
die("dotest: program aborted\n")
if ($code);
foreach $tail (#xfiles) {
chomp($tail);
printf("dotest: XDUP %s\n",$tail);
}
}
Here is the output of the test program:
--------------------------------------------------------------------------------
dotest: FILE abc 'xyz'
--------------------------------------------------------------------------------
dotest: FILE abc 'xyz'
dotest: FILE abc.pdf 'jkl'
--------------------------------------------------------------------------------
dotest: FILE abc 'xyz'
dotest: FILE abc.pdf 'jkl'
dotest: FILE abc(1).pdf 'jkl'
dotest: XDUP abc(1).pdf is dup of abc.pdf
--------------------------------------------------------------------------------
dotest: FILE abc 'xyz'
dotest: FILE abc.pdf 'jkl'
dotest: FILE abc(1).pdf 'jkl'
dotest: FILE abc(2) 'xyz'
dotest: XDUP abc(1).pdf is dup of abc.pdf
dotest: XDUP abc(2) is dup of abc
--------------------------------------------------------------------------------
dotest: FILE abc 'xyz'
dotest: FILE abc.pdf 'jkl'
dotest: FILE abc(1).pdf 'jkl'
dotest: FILE abc(2) 'xyz'
dotest: FILE abc(3) 'xx'
dotest: XDUP abc(1).pdf is dup of abc.pdf
dotest: XDUP abc(2) is dup of abc
--------------------------------------------------------------------------------
dotest: FILE abc 'xyz'
dotest: FILE abc.pdf 'jkl'
dotest: FILE abc(1).pdf 'jkl'
dotest: FILE abc(2) 'xyz'
dotest: FILE abc(3) 'xx'
dotest: FILE abc(3) 'xzy'
dotest: XDUP abc(1).pdf is dup of abc.pdf
dotest: XDUP abc(2) is dup of abc
--------------------------------------------------------------------------------
dotest: FILE abc 'xyz'
dotest: FILE abc.pdf 'jkl'
dotest: FILE abc(1).pdf 'jkl'
dotest: FILE abc(2) 'xyz'
dotest: FILE abc(3) 'xx'
dotest: FILE abc(3) 'xzy'
dotest: FILE def 'blah'
dotest: XDUP abc(1).pdf is dup of abc.pdf
dotest: XDUP abc(2) is dup of abc
--------------------------------------------------------------------------------
dotest: FILE abc 'xyz'
dotest: FILE abc.pdf 'jkl'
dotest: FILE abc(1).pdf 'jkl'
dotest: FILE abc(2) 'xyz'
dotest: FILE abc(3) 'xx'
dotest: FILE abc(3) 'xzy'
dotest: FILE def 'blah'
dotest: FILE def(3) 'blah'
dotest: XDUP def(3) is dup of def
dotest: XDUP abc(1).pdf is dup of abc.pdf
dotest: XDUP abc(2) is dup of abc
--------------------------------------------------------------------------------
dotest: FILE abc 'xyz'
dotest: FILE abc.pdf 'jkl'
dotest: FILE abc(1).pdf 'jkl'
dotest: FILE abc(2) 'xyz'
dotest: FILE abc(3) 'xx'
dotest: FILE abc(3) 'xzy'
dotest: FILE def 'blah'
dotest: FILE def(3) 'blah'
dotest: FILE def.pdf 'blah'
dotest: XDUP def(3) is dup of def
dotest: XDUP abc(1).pdf is dup of abc.pdf
dotest: XDUP abc(2) is dup of abc
readdir() reads files not like ls but by order its places in directory.
There is working variant of your program, but it works wrong, not how you want.
Please correct it itself.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
#include <pwd.h>
int main(){
int m;
char path[256],downloads[256],substr[256],buf[160],*ptr;
DIR *dir,*cmpdir;
struct dirent entry,cmpentry,*pe;
strcpy(path,getenv("HOME"));
if(path==NULL){//get HOME path
strcpy(path,getpwuid(getuid())->pw_dir);
}
strcpy(downloads,"/Downloads");
// strcpy(downloads,"/tmp/down");
strcat(path,downloads);errno=0; //make ~/Downloads
if(chdir(path)!=0){
m = errno;strcpy(buf,strerror(m));fprintf(stdout,"%d %s\n",m,buf);
return -1;
}
errno=0;
if((dir=opendir(path))==NULL){ //open directory
m=errno;strcpy(buf,strerror(m));fprintf(stdout,"%d %s\n",m,buf);
return 1;
}
while((pe=readdir(dir))!=NULL){entry=*pe;
errno=0;if((cmpdir=opendir(path))==NULL){m=errno;
strcpy(buf,strerror(m));fprintf(stdout,"%d %s\n",m,buf);
return -1;
}
}
while((pe=readdir(cmpdir))!=NULL){cmpentry=*pe;
if((entry.d_name[0]!='.')&&(strncmp(entry.d_name,"..",2)!=0)
&&(strcmp(entry.d_name,cmpentry.d_name)!=0)){
fprintf(stdout,"%s %s\n",entry.d_name,cmpentry.d_name);fflush(stdout);
ptr=strstr(cmpentry.d_name,entry.d_name);
if(ptr!=NULL){strcpy(substr,ptr);
fprintf(stdout,"%s\n",cmpentry.d_name);
}
}
}
return 0;}
Related
I am trying to solve the question
Write a C program to display all the files from the current directory and its subdirectory
whose size is greater than ānā Bytes Where n is accepted from the user through command
line.
My code
#include<stdio.h>
#include<unistd.h>
#include<sys/stat.h>
#include<dirent.h>
#include<stdlib.h> //atoi() for conversion of string to int
#include<string.h>
void print_file_names(char dir_name[100],long nByte);
int main(int argc, char *argv[])
{
DIR *dir;
struct dirent *dirent;
struct stat st;
long nByte;
if(argc != 2)
{
printf("Invalid number of argument...!");
return 0;
}
nByte = atoi(argv[1]);
dir = opendir(".");
while((dirent = readdir(dir)) != NULL)
{
if(dirent->d_type == 4) // folder or directory
{
print_file_names(dirent->d_name,nByte);
}else
{
stat(dirent->d_name,&st);
if(st.st_size > nByte)
{
printf("Directory Name = Current -- File Name = %s -- Size = %ld\n",dirent->d_name,st.st_size);
}
}
}
closedir(dir);
}
void print_file_names(char dir_name[100],long nByte)
{
DIR *dir;
struct dirent *dirent;
struct stat st;
int size;
if(strcmp(dir_name,".") == 0 || strcmp(dir_name,"..") == 0 || dir_name[0] == '.')
{
return;
}
dir = opendir(dir_name);
while((dirent = readdir(dir)) != NULL)
{
if(dirent->d_type == 8) //file
{
stat(dirent->d_name,&st);
size = st.st_size;
if(size > nByte)
{
printf("Directory Name = %s -- File Name = %s -- Size = %d\n",dir_name,dirent->d_name,size);
}
}
}
closedir(dir);
}
The output of above code is as follows
Directory Name = Current -- File Name = q2.c -- Size = 870
Directory Name = Current -- File Name = a.out -- Size = 17112
Directory Name = adir -- File Name = new.txt -- Size = 43131868
Directory Name = adir -- File Name = temp.txt -- Size = 43
Directory Name = Current -- File Name = newFile.txt -- Size = 39
Directory Name = Current -- File Name = q5.c -- Size = 1592
Not all sizes are wrong but some are wrong.
Expected output is
Directory Name = adir -- File Name = new.txt -- Size = 40
for new.txt is containing only 30 - 40 characters but st.st_size returning to large number.
#include<stdio.h>
#include<unistd.h>
#include<sys/stat.h>
#include<dirent.h>
#include<stdlib.h> //atoi() for conversion of string to int
#include<string.h>
void print_file_names(char dir_name[100],long nByte);
int main(int argc, char *argv[])
{
DIR *dir;
struct dirent *dirent;
struct stat st;
long nByte;
if(argc != 2)
{
printf("Invalid number of argument...!");
return 0;
}
nByte = atoi(argv[1]);
dir = opendir(".");
while((dirent = readdir(dir)) != NULL)
{
if(dirent->d_type == DT_DIR) // folder or directory
{
print_file_names(dirent->d_name,nByte);
}else
{
stat(dirent->d_name,&st);
if(st.st_size > nByte)
{
printf("Directory Name = Current -- File Name = %s -- Size = %ld\n",dirent->d_name,st.st_size);
}
}
}
closedir(dir);
}
void print_file_names(char dir_name[100],long nByte)
{
DIR *dir;
struct dirent *dirent;
struct stat st;
int size;
char path[100];
if(strcmp(dir_name,".") == 0 || strcmp(dir_name,"..") == 0 || dir_name[0] == '.')
{
return;
}
dir = opendir(dir_name);
while((dirent = readdir(dir)) != NULL)
{
if(dirent->d_type == DT_REG) //regular file
{
path[0] = '\0';
strcat(path,dir_name);
strcat(path,"/");
strcat(path,dirent->d_name);
stat(path,&st);
size = st.st_size;
if(size > nByte)
{
printf("Directory Name = %s -- File Name = %s -- Size = %d\n",dir_name,dirent->d_name,size);
}
}
}
closedir(dir);
}
**When file is in subfolder stat() new path as stat("subfolder/file.txt",&st);
So I create a path variable for every file in a subfolder.
and dirent->d_name give only file.txt**
So, what I'm trying to do is, at first create a file in a table format then read that file and put that file in 4 different dynamic arrays using struct and print them in order
So, here is the struct I'm using: I used capacity = 5 to change the size of dynamic array later but still don't know how to change it
struct score{
char *str1;
char *str2;
int *num1;
int *num2;
};
int main(){
int capacity = 5;
struct score table;
table.str1=(char *)malloc(sizeof(int)*capacity);
table.str2=(char *)malloc(sizeof(int)*capacity);
table.num1=(int *)malloc(sizeof(int)*capacity);
table.num2=(int *)malloc(sizeof(int)*capacity);
After I created a File to write:
inFile = fopen("Subject.txt", "w");
if(inFile == NULL)
{
printf("Error!");
exit(1);
}
char names[] = {"Joe Math 52 85\nBilly Phy 65 70\nSophia Chem 86 71"};
fprintf(inFile,"%s",names);
fclose(inFile);
At the end reading a File and putting them in arrays:
inFile = fopen("Subject.txt", "r");
if(inFile == NULL)
{
printf("Error!");
exit(1);
}
fscanf(inFile, "%s %s %d %d",table.str1, table.str2, table.num1, table.num2);
fclose(inFile);
for(i=0;i<6;i++){
printf("%s %s %d %d\n",table.str1, table.str2, table.num1, table.num2);
}
So, I need this code to print like this, and I couldn't do it:
Name Subj. Test1 Test2
------------------------
Joe Math 52 85
Billy Phy 65 70
Sophia Chem 86 71
Here is my full Code just in case:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct score{
char *str1;
char *str2;
int *num1;
int *num2;
};
int main(){
FILE *inFile;
int num, capacity = 5, i;
struct score table;
table.str1=(char *)malloc(sizeof(int)*capacity);
table.str2=(char *)malloc(sizeof(int)*capacity);
table.num1=(int *)malloc(sizeof(int)*capacity);
table.num2=(int *)malloc(sizeof(int)*capacity);
inFile = fopen("Subject.txt", "w");
if(inFile == NULL)
{
printf("Error!");
exit(1);
}
char names[] = {"Joe Math 52 85\nBilly Phy 65 70\nSophia Chem 86 71"};
fprintf(inFile,"%s",names);
fclose(inFile);
inFile = fopen("Subject.txt", "r");
if(inFile == NULL)
{
printf("Error!");
exit(1);
}
fscanf(inFile, "%s %s %d %d",table.str1, table.str2, table.num1, table.num2);
fclose(inFile);
for(i=0;i<6;i++){
printf("%s %s %d %d\n",table.str1, table.str2, table.num1, table.num2);
}
}
You want an array of structs.
But, you've got a fixed number of scores (e.g. num1, num2). This, also, should be an array.
I think you'll be better off with a second struct. That is, struct student and struct score
And, Paul outlined how to do this with fixed limits.
In general, you could allocate things dynamically to accomodate an arbitrary number of students that have an arbitrary (and varying) number of test scores.
Based on your sample data, your input format is:
<name> <subject> <score1> <score2> ... <scoreN>
Because of this, I interpret the subject to be the students major, so it gets grouped in the student record.
Otherwise, we'd need something like:
<name> <subject1> <score1> <subject2> <score2> ... <subjectN> <scoreN>
And, then, the subject would go into the score record
To get it to work, I had to [heavily] refactor your code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct score {
int score;
};
struct student {
char *name;
char *subject;
struct score *scores;
int count;
};
int
main(void)
{
FILE *inFile;
struct student *students = NULL;
int student_count = 0;
struct student *who;
struct score *score;
const char *delim = " \t\n";
char *cp;
char buf[1000];
inFile = fopen("Subject.txt", "w");
if (inFile == NULL) {
printf("Error!");
exit(1);
}
char names[] = { "Joe Math 52 85\nBilly Phy 65 70\nSophia Chem 86 71" };
fprintf(inFile, "%s", names);
fclose(inFile);
inFile = fopen("Subject.txt", "r");
if (inFile == NULL) {
printf("Error!");
exit(1);
}
while (1) {
// get a line
cp = fgets(buf,sizeof(buf),inFile);
if (cp == NULL)
break;
// get the student name
cp = strtok(buf,delim);
if (cp == NULL)
continue;
// allocate new student record
students = realloc(students,
sizeof(struct student) * (student_count + 1));
who = &students[student_count];
student_count += 1;
// save the student name
who->name = strdup(cp);
// get the subject and save it
cp = strtok(NULL,delim);
if (cp == NULL)
break;
who->subject = strdup(cp);
// clear out the scores array
who->count = 0;
who->scores = NULL;
// get all scores
while (1) {
cp = strtok(NULL,delim);
if (cp == NULL)
break;
// increase the size of the scores array for this student
who->scores = realloc(who->scores,
sizeof(struct score) * (who->count + 1));
score = &who->scores[who->count];
who->count += 1;
score->score = atoi(cp);
}
}
fclose(inFile);
for (who = &students[0]; who < &students[student_count]; ++who) {
printf("%10s %10s", who->name, who->subject);
for (score = who->scores; score < &who->scores[who->count]; ++score)
printf("%4d",score->score);
printf("\n");
}
return 0;
}
Here's the program output:
Joe Math 52 85
Billy Phy 65 70
Sophia Chem 86 71
I think you want an array of structs with one array element for each student. Now you are using one struct to hold arrays of the individual pieces of information.
The array would look like:
#define MAX_NAME 30
#define MAX_STUDENTS 10
struct score{
char str1[MAX_NAME];
char str2[MAX_NAME];
int num1;
int num2;
};
struct score table[MAX_STUDENTS];
With this definition you don't need to malloc memory (it is simpler, but not flexible).
You read the information into the array as:
int i=0;
while (fscanf(inFile, "%30s %30s %d %d",table[i].str1, table[i].str2,
&table[i].num1, &table[i].num2) == 4) {
i++;
}
In my program, I am trying to opens the text file provided at the command-line, and then creates two new text files values1.txt and values2.txt. The file from the command line contains 100 unique integer numbers. Half of the numbers are copied into values1.txt, the other half is copied into values2.txt.
However, when I tried to do it for values1.txt, I got the following values:
101
32758
0
0
176197744
32764
3
0
176197728
32764
0
0
-78325960
32758
0
0
1
0
-78326000
32758
0
0
1700966438
0
-78325096
32758
176197896
32764
176197952
32764
-78326000
32758
0
0
-80547345
32758
0
0
176197952
32764
0
0
0
0
0
0
-78326000
32758
-82942073
32758
8
Here is my code:
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
int cfileexists(const char * filename){
/* try to open file to read */
FILE *file;
if (file = fopen(filename, "r")){
fclose(file);
return 1;
}
}
int main(int argc,char*argv[]){
char *p= argv[1];
int numArray[100];
int i=0;
int sum1arr[50];
int sum2arr[50];
if (! cfileexists(p)){
printf("Error, unable to locate the data file %s\n", p);
return 100;
}
for(i;i<100;i++){
FILE *stream=fopen(p,"r");
while(!feof(stream)){
fscanf(stream,"%d",&numArray[i]);
}
FILE * fPtr = NULL;
fPtr = fopen("values1.txt", "w");
for(int j=0;j<50;j++){
fprintf(fPtr,"%d\n",numArray[j]);
}
}
}
For comparison; this is the source txtfile:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
The for statement has too many cycles, you should use the read cycle to also write, you also can use fscanf return to verify whe the file reaches it's end. If you don't need to save the values you can even use on singe int to temporarily store the value till it's written.
Here is a possibe implementation with comments:
Live demo
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int cfileexists(const char *filename)
{
/* try to open file to read */
FILE *file;
if ((file = fopen(filename, "r")))
{
fclose(file);
return 1;
}
return 0; //return 0 if file not found
}
int main(int argc, char *argv[])
{
if(argc != 2){ //check number of arguments
puts("Wrong number of arguments");
return(EXIT_FAILURE); //EXIT_FAILURE macro is more portable
}
FILE *stream;
FILE *fPtr = NULL;
FILE *fPtr2 = NULL;
int numArray[100];
int i = 0;
fPtr = fopen("values1.txt", "w");
fPtr2 = fopen("values2.txt", "w");
//you can use fopen to check file nstead of the
//function, it returns null if no file is opened
if (!(stream = fopen(argv[1], "r")))
{
perror("Error, unable to locate the data file"); //also prints error signature
return EXIT_FAILURE;
}
//check input, stop when there is nothing else to read
while (fscanf(stream, "%d", &numArray[i]) == 1 && i < 100)
{
if(i < 50)
fprintf(fPtr, "%d\n", numArray[i]); //write to file 1
else
fprintf(fPtr2, "%d\n", numArray[i]); //write to file 2
i++;
}
fclose(stream);
fclose(fPtr);
fclose(fPtr2);
}
Here's a different approach that uses getline():
#include <stdio.h>
#include <stdlib.h>
#define SPLIT_POINT 50
int main(void) {
char filename[] = "test";
FILE *fp = fopen(filename, "r");
if (!fp) {
fprintf(stderr, "Couldn't open %s\n", filename);
}
// Check file open (as above) left out for brevity
FILE *out1 = fopen("values1.txt", "w");
FILE *out2 = fopen("values2.txt", "w");
char *line = NULL;
size_t n = 0, i = 0;
ssize_t len = 0;
while ((len = getline(&line, &n, fp)) != EOF) {
// Select which output file to write to
FILE *out = i < SPLIT_POINT ? out1 : out2;
// getline includes the newline - remove this
if (i == SPLIT_POINT - 1 && len > 0) {
line[--len] = 0;
}
// Write to the relevant output file
fprintf(out, "%s", line);
i++;
}
fclose(fp);
fclose(out1);
fclose(out2);
free(line);
return 0;
}
If you don't care about removing newlines, you could simplify the getline() call - just don't bother with the len variable.
How to read and store each column in the following text from a file into an array
A17ke4004 44 66 84
A17ke4005 33 62 88
A17ke4008 44 66 86
The first column should be string and the rest should be integer
Here is a simple code that do the job.
First put your text inside a test.txt file, save it in C source code path.
test.txt
A17ke4004 44 66 84
A17ke4005 33 62 88
A17ke4008 44 66 86
Code
#include <stdio.h>
int main (void)
{
FILE *fp = NULL;
char *line = NULL;
size_t len = 0;
size_t read = 0;
char string[10][32];
int a[10], b[10], c[10];
int count = 0;
fp = fopen("test.txt", "r");
if(fp != NULL){
while((read = getline(&line, &len, fp)) != -1){
sscanf(line, "%s%d%d%d", string[count], &a[count], &b[count], &c[count]);
printf("<%s> - <%d> - <%d> - <%d>\n", string[count], a[count], b[count], c[count]);
count++;
}
}else{
printf("File can't open\n");
}
return 0;
}
Compile, Run
gcc -Wall -Wextra te.c -o te
./te
If you have more than 10 lines you should increase the arrays dimension.
Hope this help you.
I want to print an integer from 6th column of last line of an input file "out".
Following is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int len = 0;
int n2 = 0;
int n3 = 0;
char line[1000];
char *pch;
char c[6] = "ATOM ";
FILE *fp = fopen("1PGB.pdb", "r");
FILE *op = fopen("out", "w");
if (fp == NULL || op == NULL) {
fprintf(stderr, "Error opening file.\n");
exit(1);
} else {
while (fgets(line, sizeof(line), fp) != 0)
if ((pch = strstr (line, c)) != NULL)
fprintf(op, "%s\n", line);
}
fclose(fp);
fclose(op);
FILE *ip = fopen("out", "r");
fseek(ip, 1, SEEK_END);
if (fgets(line, len, ip) != NULL)
puts(line);
else
printf("Error\n");
fclose(ip);
}
It is expected to return the last line of the file "out".
It gives output: Error
The last few lines of the file out are:
ATOM 427 N GLU A 56 7.248 9.043 7.175 1.00 16.36 N
ATOM 428 CA GLU A 56 6.283 8.177 6.480 1.00 19.22 C
ATOM 429 C GLU A 56 6.780 7.744 5.081 1.00 22.26 C
ATOM 430 O GLU A 56 7.521 8.520 4.401 1.00 23.58 O
ATOM 431 CB GLU A 56 4.960 8.864 6.307 1.00 19.26 C
ATOM 432 CG GLU A 56 4.093 8.873 7.512 1.00 19.10 C
ATOM 433 CD GLU A 56 2.702 9.417 7.201 1.00 18.54 C
ATOM 434 OE1 GLU A 56 2.544 10.440 6.499 1.00 18.16 O
ATOM 435 OE2 GLU A 56 1.737 8.791 7.641 1.00 20.42 O
ATOM 436 OXT GLU A 56 6.410 6.617 4.667 1.00 24.74 O
And I want to print the integer "56" in 6th col of the last line.
output file omitted:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int len = 0;
int n2 = 0;
int n3 = 0;
int result=0;
char line[1000];
char lastline[1000]="";
char *pch;
char c[6] = "ATOM ";
FILE *fp = fopen("1PGB.pdb", "r");
//FILE *op = fopen("out", "w");
if (!fp) {
fprintf(stderr, "Error opening file.\n");
exit(1);
} else {
while (fgets(line, sizeof(line), fp) != 0)
if ((pch = strstr (line, c)) != NULL){
strcpy(lastline,line); //save content of the last output
printf("%s", line);
}
}
fclose(fp);
if(*lastline){
strtok(lastline," "); //skip first field
for(int i=0;i<4;i++) // skip next 4 fields (5 in total)
strtok(NULL," ");
sscanf(strtok(NULL," "),"%d",&result);//get and convert the 6th field
printf("LastLine: %d\n",result); //print it
}
return 0;
}