-1

I'm trying to do this in C, I have some code in Python but I can't figure how to make it work in C, I'm used to high level languages, and C is really new to me, maybe you can help me to translate it, I have nothing so far as I don't know where to begin ...

Python code:

archivo = open('passwd.txt')
for linea in archivo:
        campos = linea.strip().split(':')
        print 'User',campos[0],'has shell',campos[6]
archivo.close()

passwd.txt is the following:

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh

The output should be:

User root has shell /bin/bash
User daemon has shell /bin/sh
User bin has shell /bin/sh

Can anyone help me?

4 Answers4

1

It is quite a bit more complex, but basically there are two key things you need to know. I'm not going to tell you how to use them to do what you want to do, but just show how they can be used.

The first is the reading the file line by line. This can be done as follows: (Source)

FILE *file = fopen ( filename, "r" );
char line [ 128 ]; /* or other suitable maximum line size */
while ( fgets ( line, sizeof line, file ) != NULL ) /* read a line */
{
  fputs ( line, stdout ); /* write the line */
}
fclose ( file );

The second one is to parse the line. The best tool here is the strtok. (Source of example)

 const char string[] = "words separated by spaces -- and, punctuation!";
 const char delimiters[] = " .,;:!-";
 char *token, *cp;

 ...

 cp = strdupa (string);                /* Make writable copy.  */
 token = strtok (cp, delimiters);      /* token => "words" */
 token = strtok (NULL, delimiters);    /* token => "separated" */
 token = strtok (NULL, delimiters);    /* token => "by" */
 token = strtok (NULL, delimiters);    /* token => "spaces" */
 token = strtok (NULL, delimiters);    /* token => "and" */
 token = strtok (NULL, delimiters);    /* token => "punctuation" */
 token = strtok (NULL, delimiters);    /* token => NULL */

Put the two together, and figure out how to get the right nodes, and you're set. Good luck!

PearsonArtPhoto
  • 38,970
  • 17
  • 111
  • 142
1

@MatteoItalia brings up a good point in the comments (about piecing C together this way). This question was originally posted stating that it was part of an assignment - as Matteo indicates, I would not suggest this process for any sort of 'real' code.


The reason you will see people get frustrated when people don't show what they've done is because most people here love learning and figuring things out. I don't belong in the same room as most of the people on this site, but I think we all share that :)

I know absolutely nothing about C, but here is what I would do to figure out your issue. As mentioned by others, the internet and some dot-connecting can help you solve basically anything, so make sure to use it :)

First things first - how to open files in C? Let's Google it. Skip to the part where it talks about opening and see the code is something like:

FILE *fp;
fp=fopen("test.txt", "r");

I know I need to put this into a file that will be compiled with the C compiler, but I have no idea how to run it (using Linux). Google again. Looks like you use gcc, -o looks like it means output and will return a file named whatever I type, and the final argument is the C file itself.

gcc -o learning learning.c

Now I get errors when I compile/run, and I'm going to assume its because I need to do a little more than just type the code above. Google a little more. Looks like I need to add something called 'headers'. These look like Python libraries, maybe they provide additional functionality (from my limited Python experience, I know that C seems to be considered extremely optimized, so perhaps part of that optimization comes from not including certain features as 'built-ins'. Again, not sure, just guessing still).

#include <stdio.h>
#include <conio.h>
void main() {
  FILE *fp;
  fp = fopen("passwrd.txt", "a");
  fprintf(fp, "%s\n ", "Hello World, Where there is will, there is a way.");
  fclose(fp) ;
}

For me this causes an error with conio.h. I'll look into it later, but delete for now and try again. Now it works, adding that line to the file. However I don't want this - I want to read the file. I'll try changing a to r (since that looks like the Python a, and I'm assuming it means append; r will read). I'll also cut out the other arguments to fprint and see what happens. No dice, apparently I need to learn how to read a file. Google and I see this:

while( ( ch = fgetc(fp) ) != EOF )
   printf("%c",ch);

I drop that in my code in place of fprintf(fp);, get another error about undeclared variables and libraries, add them in and get the following, which works:

#include <stdio.h>
#include <stdlib.h>

void main() {
  char ch, file_name[25];
  FILE *fp;
  fp = fopen("passwd.txt", "r");

  while( ( ch = fgetc(fp) ) != EOF )
        printf("%c",ch);

  fclose(fp);
}

Now I need to print the first and the last values when a string is split. No clue how to do that, let's check the internet (and SO). Alright, let's drop in a new library and see if we can split stuff. I'll save the copy/paste, but I run into more and more errors. I don't know much about programming, but everything I come across seems to indicate errors with allocations, variable declarations, etc. I finally get something working (after finding a new way to read lines from a file - the other way looks like it was characters). Combining this with what I learned earlier about fprint (looks like it behaves like string formatting in Python), I get this:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main ( void )
{
  char *token;
  char *search = ":";
  char line[256];
   static const char filename[] = "passwd.txt";
   FILE *file = fopen ( filename, "r" );
   if ( file != NULL )
   {
      char line [ 128 ];
      while ( fgets ( line, sizeof line, file ) != NULL )
      {
         token = strtok(line, search);
         printf("First: %s\n", token);
      }
      fclose ( file );
   }
   else
   {
      perror ( filename );
   }
   return 0;
}

Now I need the end - I find this and see that I can make a bunch of calls to strtok and chunk down the string. Do some more research on how to loop and get this:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main ( void )
{
  char *token;
  char *search = ":";
  char line[256];
   static const char filename[] = "passwd.txt";
   FILE *file = fopen ( filename, "r" );
   if ( file != NULL )
   {
      char line [ 128 ]; /* or other suitable maximum line size */
      while ( fgets ( line, sizeof line, file ) != NULL ) /* read a line */
      {
         token = strtok(line, search);
         int counter;
         for (counter = 0; counter < 5; counter ++)
             strtok(0, search);
         char *last = strtok(0, search);
         printf("User %s has shell %s", token, last);
      }
      fclose ( file );
   }
   else
   {
      perror ( filename ); /* why didn't the file open? */
   }
   return 0;
}

Is it perfect? No way. Do I know what it does? Kind of, but I need to research more to better understand it. All-in-all, find a way to break it into small chunks - the answers may be in different places, but they'll almost always be there :)

Community
  • 1
  • 1
RocketDonkey
  • 36,383
  • 7
  • 80
  • 84
  • ... although, learning a new programming language just by "putting together" snippets found on the Internet is not a good idea, especially *not* for languages (like C or C++) where you may screw up everything and still not have a meaningful error (e.g. if you do mess with pointers you may get inexplicable bugs, random crashes as well as everything working seemingly fine). Also, coming from higher level languages you may completely misunderstand some stuff (typically newbies think that `char *` works like strings in other languages - WRONG). All in all, if you want to learn C *study a C book*. – Matteo Italia Dec 07 '12 at 02:44
  • @MatteoItalia I agree 100% - I think I was just trying to say that there are tons of resources to help you learn stuff. Ideally, you would sit down and read from the beginning, slowly building up to something like this (which in retrospect is a weird assignment for people who don't know anything about C :) ). I guess this was more the 'abridged' version - ideally this learning process would span weeks (or months, in my case :) ), so that every error made sense and that you actually knew what you were doing. Point taken though. – RocketDonkey Dec 07 '12 at 02:48
  • @MatteoItalia Ha, also additional context may be helpful - this was originally posted (and subsequently deleted) with a note that it was an assignment. That is why I bothered posting - if this were a 'production-level' problem, I would have left it to the experts :) I'll edit to clarify that point. – RocketDonkey Dec 07 '12 at 02:50
0

As far as i know,if you need to operate file in C. you can use fopen() to open text. http://msdn.microsoft.com/en-us/library/yeby3zcb%28v=VS.71%29.aspx And, you can use "EOF" to get every token. just like this:

while(gets() != EOF)

So, you can get every line int text, just save it in a string, and printf is OK.

0
#include <stdio.h>
#include <string.h>

int main(void) {
   FILE *fp = fopen("/etc/passwd", "r");
   char line[999];
   while (fgets(line, sizeof line, fp)) {
      char *user = strtok(line, ":");
      char *shell;
      int i;
      for (i = 0; i < 4; i++)
         strtok(0, ":");
      shell = strtok(0, ":");
      printf("User %s has shell %s\n", user, shell);
   }
   fclose(fp);
   return 0;
}

However, if /etc/passwd has empty fields, indicated by ::, then strtok will not work. You could use strsep instead, or just strchr, as in:

#include <stdio.h>
#include <string.h>

int main(void) {
   FILE *fp = fopen("/etc/passwd", "r");
   char line[999];
   while (fgets(line, sizeof line, fp)) {
      char *user = line;
      char *p = line;
      char *shell;
      int i;
      for (i = 0; i < 6; i++)
         p = strchr(p + 1, ':');
      shell = p + 1;
      strchr(user, ':')[0] = 0;
      printf("User %s has shell %s", user, shell);
   }
   fclose(fp);
   return 0;
}

On my machine, some of the so-called GECOS fields are empty, and user news has no shell.

Joseph Quinsey
  • 9,553
  • 10
  • 54
  • 77