|
Programming C, bash, Python, Perl, PHP, Java, you name it. |
|
Thread Tools | Display Modes |
|
|||
First program in C
Hello. For the last 5 days, I begun to learn C (with K&R alongside with "C primer plus" for that little bit of extra explanation).
I know it's a bit early to ask questions, but I try to push myself. So I decided to write a program in C that takes all of my .wav files in my dir and make them mp3 with tags. So far, I have this: Code:
#include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> void remove_enter( char *s ) // function to remove enter from stdin { s[strcspn( s, "\n" )] = '\0'; } int main() { char artist[40]; char album[40]; char genre[20]; char year[4]; printf("Enter artist name:\n"); // input name, move to array, remove \n fgets(artist, 256, stdin); remove_enter(artist); printf("Enter album name:\n"); fgets(album, 256, stdin); remove_enter(album); printf("Enter year:\n"); fgets(year, 256, stdin); remove_enter(year); printf("Enter genre:\n"); fgets(genre, 256, stdin); remove_enter(genre); char argv[512]; // create array to pass lame switches snprintf(argv, 512, "/usr/local/bin/lame --ta %s --tl %s --ty %s --tg %s *.wav", artist, album, year, genre); // lame to array system(argv); // pipe exec to system return 0; } I also would love some criticism about how correct is the code. (again, I know it's not much ). Thank you. |
|
|||
Quote:
Code:
$ cat test.c #include <stdio.h> int main(int argc, char *argv[]) { int i; for (i = 0; i < argc; i++) printf("%d:\t%s\n", i, argv[i]); return 0; } $ gcc test.c $ a.out 0: a.out $ a.out 1 2 three 0: a.out 1: 1 2: 2 3: three $ Writing lots of simple programs (less than 20 lines...) like what I have indicated above is very important as you teach yourself how to answer your own questions. This is the sign of a good programmer -- one who thinks through the problem, identifies what they know, what they don't know, & does the research needed to answer unknowns themselves. Quote:
Once you have mastered The C Programming Language, I would recommend C Traps and Pitfalls next. Andrew Koenig is also one of the original AT&T elite who penned seminal books on the subject. C Traps and Pitfalls points out where C inconsistencies frequently bite newbies & experienced professionals alike. |
|
|||
For bonus points, you might also want to consider how your program could be written as a shell script. After all, the logic of your program is simply manipulating some strings followed by spawning another shell to execute a constructed command.
The problem with many professional C programmers (especially if they only have proficiency in the one language...) is that they think that everything can & should be written in C. While it is true that C is flexible enough to handle general usage, it may not be the most advantageous choice. Scripting has its place, & many scripting languages have special facilities for handling string manipulations far more flexibly than C. Yes, shell scripts are limited to what can be spliced together via sed(1), grep(1), awk(1), etc., the newer scripting languages such as Perl, Python, & Ruby excel at string manipulations. Learning regular expressions can be a very useful tool in your ever-expanding bag of tricks. |
|
|||
Thank you VERY much ocicat for the advice and the help.
As for the second post, I've already done that in perl. I want to achieve it in C (as well as some other simple scripts) just for the excercise and the excitement. I see that many simple scripts can be a hell to achieve with C, but they are a great learning experience. No pain, no gain after all. |
|
|||
To further elucidate, your initial code posted was interactive -- requiring user input during execution. Specifying everything (all titles, artists, tracks...) on the command-line would be cumbersome & scale very poorly.
If you have lots of files to process, you might want to consider making the application more batch-oriented as opposed to interactive. To do this, you might want to look at figuring out a file format which would then be parsed by your code. All information could be manually written to a text file which is then read & processed by program logic. The file would include all information needed to tag tracks. Processing different tracks would then mean that only this one text file would need to be modified. Since I suspect this application is simply educational in nature, you might consider mixing command-line input with interactive prompts for specific values -- track names, artist names, etc. In this fashion, filenames could be specified at the command-line explicitly and/or via wildcards, & then the program logic would then ask for more information for each specified track. Just a thought. There are lots of ways of doing the processing desired. Last edited by ocicat; 11th November 2011 at 11:46 PM. |
|
|||
But he's trying to learn C so it doesn't matter that using a shell might be better.
|
|
|||
After one week and not so much time on my hands, I achieved it. I have some questions about the way I did it though.
With the first try, I achieve it like this: Code:
#include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <stdlib.h> #include <stddef.h> void remove_enter( char *s ) /* function to remove enter from stdin */ { s[strcspn( s, "\n" )] = '\0'; } int main(int argc, char *argv[]) { char artist[150]; char album[150]; char genre[40]; char year[8]; char track[50]; /* check for command line arguments and print msg */ if (argc < 2) { fprintf(stderr, "Usage: %s filename\n", argv[0]); exit(1); } printf("Enter artist name:\n"); /* ask for input, read to array, remove enter */ fgets(artist, sizeof(artist), stdin); remove_enter(artist); printf("Enter album name:\n"); fgets(album, sizeof(album), stdin); remove_enter(album); printf("Enter year:\n"); fgets(year, sizeof(year), stdin); remove_enter(year); printf("Enter genre:\n"); fgets(genre, sizeof(genre), stdin); remove_enter(genre); int pid, status; int i; /* count files *.wav and fork() with counter i<=tracks_number + ask for track name */ for (i = 1; i < argc; i++) { printf("Enter track name:\n"); fgets(track, sizeof(track), stdin); remove_enter(track); pid=fork(); if (pid==0) { char *command[] = {"/usr/local/bin/lame","-V 2","--tt",track,"--ta",artist, "--tl",album, "--ty",year, "--tg",genre,argv[i],NULL}; execvp("lame", command); sleep(1); } else { wait(&status); } } return 0; } Code:
/* same as above to save space */ #define LEN 1000 struct tag_t { char artist[LEN]; char album[LEN]; char year[LEN]; char genre[LEN]; char track[LEN]; } taglist; void remove_enter( char *s ) /* function to remove enter from stdin */ { s[strcspn( s, "\n" )] = '\0'; } int main(int argc, char *argv[]) { int max; /* check for command line arguments and print msg */ if (argc < 2) { fprintf(stderr, "Usage: %s filename\n", argv[0]); exit(1); } printf("Enter artist name:\n"); /* ask for input, read to array, remove enter */ char *artist = (char*) malloc(50 *sizeof(char)); fgets(taglist.artist, LEN, stdin); remove_enter(taglist.artist); /* same for album, year and genre to save space in post */ int pid, status; int i; /* count files *.wav and fork() with counter i<=tracks_number + ask for track name */ for (i = 1; i < argc; i++) { printf("Enter track name:\n"); fgets(taglist.track, LEN, stdin); remove_enter(taglist.track); pid=fork(); if (pid==0) { char *command[] = {"/usr/local/bin/lame","-V 2","--tt",taglist.track,"--ta",taglist.artist, "--tl",taglist.album, "--ty",taglist.year, "--tg",taglist.genre,argv[i],NULL}; execvp("lame", command); sleep(1); } else { wait(&status); } } free(artist); return 0; } Sorry for the very long post and a big thank you to anyone who reads it. Comments about the structure of the code are also welcome. |
|
|||
This is unclear. Please clarify.
|
|
|||
|
|
|||
Ocicat, I cannot thank you enough for your help. I understand fully what you said about the structures and also thanks for the clarification or the function.
When I enter a name (for example in 'artist') and it has 40 characters, taglist.artist stores it properly (with malloc() ). The problem is when I pass the value in char *command[LEN], it stores only the 30 first characters. Do I need to use malloc() on every array object? And if yes, how can I approach this properly? I couldn't find any source about this... And a last question for free(). When I use it on a char object inside a structure, I target it by name (for this example free(artist)) or by first referring to the structure name (free(taglist.artist))? Is it a good solution to free after use the entire structure by free(taglist)? I hope I'm making some sense... |
|
||||
Quote:
Code:
printf("Enter artist name:\n");/* ask for input, read to array, remove enter */ char *artist = (char*) malloc(50 *sizeof(char)); fgets(taglist.artist, LEN, stdin); remove_enter(taglist.artist); Recognize that the name "artist" is being used in two completely different contexts. One, naming a field within a global structure. The other, a variable defined within main(). To illustrate, study the following example: Code:
$ cat addresses.c #include <stdio.h> struct struct_name { int foo; } global_sn_instance; int main() { struct struct_name sn_instance; int foo; printf("global struct:\t%u\n", (void*) &global_sn_instance.foo); printf("local struct:\t%u\n", (void*) &sn_instance.foo); printf("local variable:\t%u\n", (void*) &foo); return 0; } $ gcc addresses.c $ a.out global struct: 1006645888 local struct: 3485315520 local variable: 3485315516 $ Quote:
Quote:
Code:
$ cat memory.c #include <stdio.h> #include <stdlib.h> struct a { char *s; }; struct b { char s[8]; }; int main() { struct a a; struct b *p; a.s = (char*) malloc(8 * sizeof(char)); scanf("%s", a.s); p = (struct b*) malloc(sizeof(struct b)); scanf("%s", p->s); printf("a:\t%s\n", a.s); printf("b:\t%s\n", p->s); free(a.s); free(p); return 0; } $ gcc memory.c $ a.out abc xyz a: abc b: xyz $ Quote:
Last edited by ocicat; 24th November 2011 at 04:21 PM. |
|
|
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
DragonFly BSD disklabel program changes. | J65nko | News | 0 | 18th February 2010 01:59 AM |
Can't install program | guitarscn | OpenBSD General | 3 | 31st August 2009 08:40 PM |
How to learn to program under BSD? | Sunnz | Programming | 5 | 24th December 2008 11:45 PM |
Learning how to program | Solaris_Delta | Programming | 9 | 24th December 2008 07:58 PM |
run linux's program | johnzlly | OpenBSD General | 38 | 8th November 2008 12:10 PM |