FRIHOST FORUMS SEARCH FAQ TOS BLOGS COMPETITIONS
You are invited to Log in or Register a free Frihost Account!


[C] Splitting names program





Indi
(This is a question from a nother thread that i've broken out into its own thread.)

vm_yap wrote:
it is something for school. the problem is the subject that i'm taking this for is not C programming but about Operating System.

Actually when i took C programming some years ago they werent able to teach us how to manipulate arrays.

this is how the program should do.

first a user must enter his/her full name (first name, middle name, last name)

then it will output it as (last name, first name middle name)

*note: the program should be able to recognize if the names inputted has one or two or more names

*the program doesn't have to perfect, it just needs to work.

any help will do thanks again

Alright, because this is for school, it doesn't really need to be that robust or great. A lot of the stuff I'll show is just quick and dirty hacks, and not suitable for "real" programs. If anyone wants to give it a shot as a more extensible or robust C or C++ design, it's a great practice program.

First, you should start with a proper C program outline. The one you were using was not legal C, and shouldn't compile with modern compilers. A good simple outline is this:
Code:
#include <stdlib.h>

int main(void)
{
   return EXIT_SUCCESS;
}

Once you have that, you should consider the variables you're going to need. Since you will need at most 3 names (first, middle, last), you will need 3 variables:
Code:
char first_name[30];
char middle_name[30];
char last_name[30];

Even better would be to use constants to define the sizes. Also, you should set them all to null to begin with (your previous version had a bug because you did not):
Code:
#define FIRST_NAME_LENGTH 30
#define MIDDLE_NAME_LENGTH 30
#define LAST_NAME_LENGTH 30

// The + 1 is to leave room for the null  terminator
char first_name[FIRST_NAME_LENGTH + 1];
char middle_name[MIDDLE_NAME_LENGTH + 1];
char last_name[LAST_NAME_LENGTH + 1];

// Setting everything to null (memset is in <string.h>)
memset(first_name, '\0', FIRST_NAME_LENGTH + 1);
memset(middle_name, '\0', MIDDLE_NAME_LENGTH + 1);
memset(last_name, '\0', LAST_NAME_LENGTH + 1);

You're also going to need a 4th char array variable, to store the whole name when you input it. It will need to be at least as big as FIRST_NAME_LENGTH + MIDDLE_NAME_LENGTH + LAST_NAME_LENGTH + plus some extra space for the spaces between them. Adding that in and putting it all together, you get:
Code:
#include <stdlib.h>
#include <string.h>

#define FIRST_NAME_LENGTH 30
#define MIDDLE_NAME_LENGTH 30
#define LAST_NAME_LENGTH 30

#define EXTRA_NAME_SPACE 10
#define FULL_NAME_LENGTH FIRST_NAME_LENGTH + MIDDLE_NAME_LENGTH + LAST_NAME_LENGTH + EXTRA_NAME_SPACE

int main(void)
{
   // Variables for the names
   char first_name[FIRST_NAME_LENGTH + 1];
   char middle_name[MIDDLE_NAME_LENGTH + 1];
   char last_name[LAST_NAME_LENGTH + 1];
   
   char full_name[FULL_NAME_LENGTH + 1];
   
   // Setting the name variables to null
   memset(first_name, '\0', FIRST_NAME_LENGTH + 1);
   memset(middle_name, '\0', MIDDLE_NAME_LENGTH + 1);
   memset(last_name, '\0', LAST_NAME_LENGTH + 1);
   
   memset(full_name, '\0', FULL_NAME_LENGTH + 1);

   return EXIT_SUCCESS;
}


<CHECKPOINT>
Are you still with me? Do you understand everything done so far? i have created variables for each part of the name, and set those variables to null.

The next part is easy. You just input the full name. You used gets(), so i will too, but you should never use gets() in real code:
Code:
printf("Enter your full name: ");
gets(full_name);
// Better would be:
// fgets(full_name, FULL_NAME_LENGTH, stdin);

You should also have no problem sticking that into the existing code. Don't forget that gets() needs <stdio.h>:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FIRST_NAME_LENGTH 30
#define MIDDLE_NAME_LENGTH 30
#define LAST_NAME_LENGTH 30

#define EXTRA_NAME_SPACE 10
#define FULL_NAME_LENGTH FIRST_NAME_LENGTH + MIDDLE_NAME_LENGTH + LAST_NAME_LENGTH + EXTRA_NAME_SPACE

int main(void)
{
   // Variables for the names
   char first_name[FIRST_NAME_LENGTH + 1];
   char middle_name[MIDDLE_NAME_LENGTH + 1];
   char last_name[LAST_NAME_LENGTH + 1];
   
   char full_name[FULL_NAME_LENGTH + 1];
   
   // Setting the name variables to null
   memset(first_name, '\0', FIRST_NAME_LENGTH + 1);
   memset(middle_name, '\0', MIDDLE_NAME_LENGTH + 1);
   memset(last_name, '\0', LAST_NAME_LENGTH + 1);
   
   memset(full_name, '\0', FULL_NAME_LENGTH + 1);
   
   // Input full name //////////////////////////////////////////////////////////
   printf("Enter your full name: ");
   gets(full_name);
   
   return EXIT_SUCCESS;
}


<CHECKPOINT>
All we've done new at this point is added the input stuff.

Ok, now comes the tricky part. What does a name look like? The answer is, it depends on how you want to look at it.

For me, i'm going to assume the name looks like this:
[Space][First name][Space][Middle name(s)][Space][Last name][Space].
Each [Space] doesn't need to be just one space, it can be dozens, and the space at the beginning and at the end is optional. So if someone typed:
"________John__________Jacob__________Jingleheimer_______Schmidt_____"
(where '_' are spaces), it would be read as:
"[Space]John[Space]Jacob__________Jingleheimer[Space]Schmidt[Space]".

Now the other thing we need to consider is different numbers of names. If we are given only one name, then it should be considered as a last name (no first or last). If we are given two, then it should be considered as first and last (no middle). If we are given three or more, then the first one is the first name, the last one is the last name, and everything in between is middle names. So:
"Socrates": LAST="Socrates"
"Joe Blow": LAST="Blow", FIRST="Joe"
"Austin Danger Powers": LAST="Powers", FIRST="Austin", MIDDLE="Danger"
"John Jacob Jingleheimer Schmidt": LAST="Schmidt", FIRST="John", MIDDLE="Jacob Jingleheimer"

Looking at the names above, it should be clear that we want to check for a last name first, then a first name if there's anything else, and then if there's anything else after that, it's all the middle name.

So, here's the procedure:
  1. Start at the end.
  2. If the last letter is a space, keep going backwards until you find the first thing that is not a space.
  3. Make a note of where you are. This will be the end of the last name.
  4. Keep going backwards again until you find another space. Everything from there to the last spot you marked is the last name.
  5. If you're at the beginning of the full name, you're done.
  6. Otherwise, go back to the beginning.
  7. If it's a space, start skipping spaces until you get to the first thing that's not a space.
  8. If that is the same spot as the start of the last name, then there is no first name, and you're done.
  9. Otherwise, you have found the start of the first name.
  10. Now go forward until you find the last thing that is not a space. That is the end of the first name.
  11. Everything between the end of the first name and the start of the last name is the middle name(s).

Try this method with each of the names above. First, try "Socrates":
  1. Start at the end, which is an 's'.
  2. It is not a space, so there is no need to go keep going backwards.
  3. This will be the end of the last name.
  4. Keep going backwards again until you find a space or the beginning of the name. There are no spaces, so you get to the beginning of the name: 'S'. Everything from 'S' to the 's' is the last name.
  5. We're at the beginning of the full name, so we're done.

Result: last name only, "Socrates".
Now try: "_____John____Jacob_____Jingleheimer____Schmidt_____".
  1. Start at the end.
  2. The last letter is a space, so keep going backwards until you find the first thing that is not a space. That it the 't' in "Schmidt".
  3. This is the end of the last name.
  4. Keep going backwards again until you find another space. That is just before the 'S' in "Schmidt". Everything from there to the last spot you marked is the last name. That is from 'S' to 't', which is "Schmidt".
  5. If you're at the beginning of the full name, you're done. We're not, so keep going.
  6. Go back to the beginning.
  7. It's a space, so start skipping spaces until you get to the first thing that's not a space. That is the 'J' in "John".
  8. That is not the same spot as the start of the last name, so we're not done yet.
  9. This is the start of the first name.
  10. Now go forward until you find the last thing that is not a space. That is the 'n' in "John", the end of the first name. That means the first name is "John".
  11. Everything between the end of the first name and the start of the last name is the middle name(s). That is "____Jacob_____Jingleheimer____".

Try it on paper - especially squared paper so it's easy to count the spaces. You have to understand how the algorithm works before you move on, or you'll just be confused as hell.

<CHECKPOINT>
Up to this point, i described the algorithm i'm using. It's far more complicated than the one from the previous program, because it has to do far more. The last program only dealt with one or two names (and, by the way, it would crash for zero), and wasn't smart enough to detect the difference between a single name or two. This algorithm can deal with one, two, three or more names, and will correctly split it into first name, last name, and any number of middle names. If you don't understand how it works, try to write out any random name on paper and follow the algorithm, to see what's happening.

If you understand how the algorithm works, implementing it is easy.

First, you need to start at the end of the full name. That's easy to find from the length:
Code:
int length_of_full_name = strlen(full_name);

If that length is zero, we don't have a name at all (the person just pressed enter instead of entering a name). Otherwise, we need to start from there and see if there are any spaces we need to skip:
Code:
if (length_of_full_name > 0)
{
   // Skip spaces at end
   int end_of_last_name = length_of_full_name;
   
   while (end_of_last_name != 0 && isspace(full_name[end_of_last_name - 1]))
      --end_of_last_name;
   
   // At this point, end_of_last_name is at the end of the last name
   // Note that isspace() is in <ctype.h>
}

Now we need to go back to the beginning of the last name:
Code:
int start_of_last_name = end_of_last_name;

while (start_of_last_name != 0 && !isspace(full_name[start_of_last_name - 1]))
   --start_of_last_name;

// At this point, start_of_last_name is at the start of the last name

So we've already got the last name covered. Now for the first name. We start at the beginning, and skip forward while there are spaces and while we haven't got to the start of the last name:
Code:
int start_of_first_name = 0;

while (start_of_first_name != start_of_last_name && isspace(full_name[start_of_first_name]))
   ++start_of_first_name;

// At this point, we've found the start of the first name (if any)

If we've actually found a first name, we just have to find the end now, using the same pattern:
Code:
if (start_of_first_name != start_of_last_name)
{
   int end_of_first_name = start_of_first_name;
   
   while (!isspace(full_name[++end_of_first_name]))
      ;
   
   // And that takes us to the end of the first name
}

Everything between the first and last names is now the middle names. i'm not going to do the final steps, which are removing the spaces from the front and the back of the middle names, and compacting the spaces within the middle name. You should try those on your own.

So let's put that code into context. Unfortunately, i can't highlight code with colours, so it's hard to mark new additions. But all i've added is one header, a couple more variables, and then a bunch in the middle:
Code:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FIRST_NAME_LENGTH 30
#define MIDDLE_NAME_LENGTH 30
#define LAST_NAME_LENGTH 30

#define EXTRA_NAME_SPACE 10
#define FULL_NAME_LENGTH FIRST_NAME_LENGTH + MIDDLE_NAME_LENGTH + LAST_NAME_LENGTH + EXTRA_NAME_SPACE

int main(void)
{
   // Variables for the names
   char first_name[FIRST_NAME_LENGTH + 1];
   char middle_name[MIDDLE_NAME_LENGTH + 1];
   char last_name[LAST_NAME_LENGTH + 1];
   
   char full_name[FULL_NAME_LENGTH + 1];
   
   // Variables to separate the names
   int start_of_first_name = 0;
   int end_of_first_name = 0;
   int start_of_middle_name = 0;
   int end_of_middle_name = 0;
   int start_of_last_name = 0;
   int end_of_last_name = 0;
   
   // Setting the name variables to null
   memset(first_name, '\0', FIRST_NAME_LENGTH + 1);
   memset(middle_name, '\0', MIDDLE_NAME_LENGTH + 1);
   memset(last_name, '\0', LAST_NAME_LENGTH + 1);
   
   memset(full_name, '\0', FULL_NAME_LENGTH + 1);
   
   // Input full name //////////////////////////////////////////////////////////
   printf("Enter your full name: ");
   gets(full_name);
   
   // Parse name ///////////////////////////////////////////////////////
   // Get end of last name ---------------------------------
   end_of_last_name = strlen(full_name);
   
   // Skip spaces at end
   while (end_of_last_name != 0 && isspace(full_name[end_of_last_name - 1]))
      --end_of_last_name;
   
   // Get start of last name ---------------------------------
   start_of_last_name = end_of_last_name;
   
   while (start_of_last_name != 0 && !isspace(full_name[start_of_last_name - 1]))
      --start_of_last_name;
   
   // Get start of first name (by skipping spaces at start) -------------------
   while (start_of_first_name != start_of_last_name && isspace(full_name[start_of_first_name]))
      ++start_of_first_name;
   
   // Get end of first name (if any) ------------------------
   if (start_of_first_name != start_of_last_name)
   {
      end_of_first_name = start_of_first_name;
     
      while (!isspace(full_name[++end_of_first_name]))
         ;
   }
   
   // Middle name, which i don't do -------------------------
   // If you want to add this feature, make your changes here
   start_of_middle_name = end_of_first_name;
   end_of_middle_name = start_of_last_name;
   
   return EXIT_SUCCESS;
}


<CHECKPOINT>
If you understood how the algorithm works, implementing it is a snap. You can even go on from here to implement smarter ways to handle the middle name(s). It's not hard to do.

Just one more semi-tricky part to go. We know where each of the names begins and ends. Now all we need to do is copy them into the right variables.

To do this, we use strncpy(). The last name is easy:
Code:
strncpy(last_name, full_name + start_of_last_name, end_of_last_name - start_of_last_name);

(Note, if you want to be more robust, you should do min(end_of_last_name - start_of_last_name, LAST_NAME_LENGTH) as the last parameter.)

For the first name, we first have to check and see if there is one:
Code:
if (start_of_first_name != start_of_last_name)
{
   strncpy(first_name, full_name + start_of_first_name, end_of_first_name - start_of_first_name);
}


i didn't do anything for the middle name, so if you do, you might have to do more than this, depending on what you do:
Code:
strncpy(middle_name, full_name + start_of_middle_name, end_of_middle_name - start_of_middle_name);


And, putting this in the program is trivial:
Code:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FIRST_NAME_LENGTH 30
#define MIDDLE_NAME_LENGTH 30
#define LAST_NAME_LENGTH 30

#define EXTRA_NAME_SPACE 10
#define FULL_NAME_LENGTH FIRST_NAME_LENGTH + MIDDLE_NAME_LENGTH + LAST_NAME_LENGTH + EXTRA_NAME_SPACE

int main(void)
{
   // Variables for the names
   char first_name[FIRST_NAME_LENGTH + 1];
   char middle_name[MIDDLE_NAME_LENGTH + 1];
   char last_name[LAST_NAME_LENGTH + 1];
   
   char full_name[FULL_NAME_LENGTH + 1];
   
   // Variables to separate the names
   int start_of_first_name = 0;
   int end_of_first_name = 0;
   int start_of_middle_name = 0;
   int end_of_middle_name = 0;
   int start_of_last_name = 0;
   int end_of_last_name = 0;
   
   // Setting the name variables to null
   memset(first_name, '\0', FIRST_NAME_LENGTH + 1);
   memset(middle_name, '\0', MIDDLE_NAME_LENGTH + 1);
   memset(last_name, '\0', LAST_NAME_LENGTH + 1);
   
   memset(full_name, '\0', FULL_NAME_LENGTH + 1);
   
   // Input full name //////////////////////////////////////////////////////////
   printf("Enter your full name: ");
   gets(full_name);
   
   // Parse name ///////////////////////////////////////////////////////
   // Get end of last name ---------------------------------
   end_of_last_name = strlen(full_name);
   
   // Skip spaces at end
   while (end_of_last_name != 0 && isspace(full_name[end_of_last_name - 1]))
      --end_of_last_name;
   
   // Get start of last name ---------------------------------
   start_of_last_name = end_of_last_name;
   
   while (start_of_last_name != 0 && !isspace(full_name[start_of_last_name - 1]))
      --start_of_last_name;
   
   // Get start of first name (by skipping spaces at start) -------------------
   while (start_of_first_name != start_of_last_name && isspace(full_name[start_of_first_name]))
      ++start_of_first_name;
   
   // Get end of first name (if any) ------------------------
   if (start_of_first_name != start_of_last_name)
   {
      end_of_first_name = start_of_first_name;
     
      while (!isspace(full_name[++end_of_first_name]))
         ;
   }
   
   // Middle name, which i don't do -------------------------
   // If you want to add this feature, make your changes here
   start_of_middle_name = end_of_first_name;
   end_of_middle_name = start_of_last_name;
   
   // Copy the names into the proper variables //////////////////////////////
   strncpy(last_name, full_name + start_of_last_name, end_of_last_name - start_of_last_name);
   
   if (start_of_first_name != start_of_last_name)
   {
      strncpy(first_name, full_name + start_of_first_name, end_of_first_name - start_of_first_name);
     
      strncpy(middle_name, full_name + start_of_middle_name, end_of_middle_name - start_of_middle_name);
   }
   
   return EXIT_SUCCESS;
}


<CHECKPOINT>
Do you understand why the strncpy() functions are called the way they are?

And you're pretty much done. All you have to do is print the results. Here is what you should have, roughly:
Code:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FIRST_NAME_LENGTH 30
#define MIDDLE_NAME_LENGTH 30
#define LAST_NAME_LENGTH 30

#define EXTRA_NAME_SPACE 10
#define FULL_NAME_LENGTH FIRST_NAME_LENGTH + MIDDLE_NAME_LENGTH + LAST_NAME_LENGTH + EXTRA_NAME_SPACE

int main(void)
{
   // Variables for the names
   char first_name[FIRST_NAME_LENGTH + 1];
   char middle_name[MIDDLE_NAME_LENGTH + 1];
   char last_name[LAST_NAME_LENGTH + 1];
   
   char full_name[FULL_NAME_LENGTH + 1];
   
   // Variables to separate the names
   int start_of_first_name = 0;
   int end_of_first_name = 0;
   int start_of_middle_name = 0;
   int end_of_middle_name = 0;
   int start_of_last_name = 0;
   int end_of_last_name = 0;
   
   // Setting the name variables to null
   memset(first_name, '\0', FIRST_NAME_LENGTH + 1);
   memset(middle_name, '\0', MIDDLE_NAME_LENGTH + 1);
   memset(last_name, '\0', LAST_NAME_LENGTH + 1);
   
   memset(full_name, '\0', FULL_NAME_LENGTH + 1);
   
   // Input full name //////////////////////////////////////////////////////////
   printf("Enter your full name: ");
   gets(full_name);
   
   // Parse name ///////////////////////////////////////////////////////
   // Get end of last name ---------------------------------
   end_of_last_name = strlen(full_name);
   
   // Skip spaces at end
   while (end_of_last_name != 0 && isspace(full_name[end_of_last_name - 1]))
      --end_of_last_name;
   
   // Get start of last name ---------------------------------
   start_of_last_name = end_of_last_name;
   
   while (start_of_last_name != 0 && !isspace(full_name[start_of_last_name - 1]))
      --start_of_last_name;
   
   // Get start of first name (by skipping spaces at start) -------------------
   while (start_of_first_name != start_of_last_name && isspace(full_name[start_of_first_name]))
      ++start_of_first_name;
   
   // Get end of first name (if any) ------------------------
   if (start_of_first_name != start_of_last_name)
   {
      end_of_first_name = start_of_first_name;
     
      while (!isspace(full_name[++end_of_first_name]))
         ;
   }
   
   // Middle name, which i don't do -------------------------
   // If you want to add this feature, make your changes here
   start_of_middle_name = end_of_first_name;
   end_of_middle_name = start_of_last_name;
   
   // Copy the names into the proper variables //////////////////////////////
   strncpy(last_name, full_name + start_of_last_name, end_of_last_name - start_of_last_name);
   
   if (start_of_first_name != start_of_last_name)
   {
      strncpy(first_name, full_name + start_of_first_name, end_of_first_name - start_of_first_name);
     
      strncpy(middle_name, full_name + start_of_middle_name, end_of_middle_name - start_of_middle_name);
   }
   
   // Print the results //////////////////////////////////////////////////
   printf("\nThe name you have entered is:\n");
   
   // Print the last name
   printf(last_name);
   
   // Print the first name, if any
   if (strlen(first_name))
   {
      print(", %s", first_name);
     
      // Print the middle names, if any
      if (strlen(middle_name))
         printf(" %s", middle_name);
   }
   
   return EXIT_SUCCESS;
}


And you're done.

Now, i didn't actually test any of this code - that's up to you. i don't actually know if it will compile. But if you've followed along and you understand the steps, you should be able to fix it easily.
darth_revan
is isspace() function similar to if (.. ==' ')? does it have any benefits?
Indi
darth_revan wrote:
is isspace() function similar to if (.. ==' ')? does it have any benefits?

It will return true for ' ', '\t', '\v', ' ' (not the same as ' '), and many more... basically anything that counts as a space.
Related topics
Apache2Triad
Hamachi
Problem z portem COM i Firewall-em
A C program in Linux
Windows XP SP3 comming soon
Quick Question in C language
CLOSE PLEASE-Need a C++ program - upto 200frih$
Deploying a C# program
changing system time using a c program under cygwin
C/C++ Windows book names
C++ Program Basics
New to programming..advise please.
Nonexistent files consuming my hard drive
Introduction to C++ Programming+First Program
Reply to topic    Frihost Forum Index -> Scripting -> Others

FRIHOST HOME | FAQ | TOS | ABOUT US | CONTACT US | SITE MAP
© 2005-2011 Frihost, forums powered by phpBB.