4

I'm new to C so forgive me if this is too obvious, but I am having an issue finding the error in my code that is leading to a segmentation fault. I believe the issue may be in the usage of malloc(), but I am not positive.

Here is the code:

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

#define         MAX_STRING      20

char*   getFirstName    (char*  firstName
                        )
{
  char* myfirstName = (char*)malloc(strlen(firstName)+1);
  printf("Please enter your first name: ");
  fgets(firstName,MAX_STRING,stdin);
  return(myfirstName);
}


char*   getLastName     (char* lastName
                    )
{
  char* mylastName = (char*)malloc(strlen(lastName)+1);

  printf("Please enter your last name: ");
  fgets(lastName,MAX_STRING,stdin);
  return(mylastName);
}


char*   getNickName     (char*  nickName
                        )
{
  char* mynickName = (char*)malloc(strlen(nickName)+1);
  printf("Please enter your nick name: ");
  fgets(nickName,MAX_STRING,stdin);
  return(mynickName);
}


char*   getCompleteName (const char*    firstName,
                         const char*    lastName,
                         const char*    nickName,
                         char*          completeName
                        )
{
  snprintf(completeName,MAX_STRING,"%s \"%s\"    %s",firstName,nickName,lastName);
}


int     main    ()
{
  char*         firstName;
  char*         lastName;
  char*         nickName;
  char*         completeName;

  firstName     = getFirstName(firstName);
  lastName      = getLastName(lastName);
  nickName      = getNickName(nickName);

  completeName  = getCompleteName(firstName,lastName,nickName,completeName);
  printf("Hello %s.\n",completeName);
 free(firstName);
 free(lastName);
 free(nickName);
 return(EXIT_SUCCESS);
}

Does it seem that I am using malloc() in the correct way?

SciGuy
  • 59
  • 1
  • 6
  • 2
    There are a host of things wrong in this code beyond just the malloc, including multiple undefined behavior invokes reading data into indeterminate memory locations and improper use of `strlen`. Beyond the casts on `malloc` [(which you should *not* do)](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc?s=1|7.2290), about the only way to mess that function up is failing to validate its return value or leaking any memory it returns to you. There is plenty else you should work on in this code. – WhozCraig May 23 '15 at 06:15

5 Answers5

2

The preferred way to write a malloc call is

T *p = malloc( N * sizeof *p );

calloc is similar:

T *p = calloc( N, sizeof *p );

The cast is unnecessary, and under C89 compilers can mask a bug.

The problem with this call

  char* myfirstName = (char*)malloc(strlen(firstName)+1);

is the that firstName parameter hasn't been initialized; it doesn't point to a string, so calling strlen on it is undefined. In this case, you should use the MAX_STRING constant instead:

char *myFirstName = malloc( (MAX_STRING + 1) * sizeof *myFirstName );

In this case, sizeof *myFirstName is redundant (sizeof (char) is 1 by definition), but it doesn't hurt anything, and if you decide to change the type of myFirstName to wchar * for some crazy reason, the call will still work properly.

John Bode
  • 119,563
  • 19
  • 122
  • 198
1

I'm also new, but I think your problem is here:

char*         firstName;

firstName     = getFirstName(firstName);

char* myfirstName = (char*)malloc(strlen(firstName)+1);

you are implementing strlen on uninitialize char pointer. You have to specify a max len (#define MAX_SIZE 64) and use it as you do not know the length of the names.

Also consider this, the first 3 functions does the same, you should consider having one function instead.

Hope I helped

Shay Gold
  • 403
  • 4
  • 14
1

The functions you have written to enter data do not use their parameters (or they use them incorrectly). Thus, it makes no sense to declare them like:

char*   getFirstName    (char*  firstName );

Within the functions, memory is allocated and a pointer to the memory is returned.

Moreover, this statement:

char* myfirstName = (char*)malloc(strlen(firstName)+1);

is invalid. The argument for parameter firstName was not initialized and does not point to any string.

Or you try to allocate memory and save the corresponding address in variable myfirstName:

char* myfirstName = (char*)malloc(strlen(firstName)+1);

but then try to read data using pointer firstName:

fgets(firstName,MAX_STRING,stdin);

The function getCompleteName is also invalid. Again, there was no allocated memory that should be pointed to by completeName where you try to concatenate other strings. And the function returns nothing.

char*   getCompleteName (const char*    firstName,
                         const char*    lastName,
                         const char*    nickName,
                         char*          completeName
                        )
{
  snprintf(completeName,MAX_STRING,"%s \"%s\"    %s",firstName,nickName,lastName);
}

Take into account that function fgets also includes in the target array the new line character.

Thus, correct functions can look like the following definition below:

char*   getFirstName()
{
    char* myfirstName = ( char* )malloc( MAX_STRING );

    printf( "Please enter your first name: " );

    fgets( myfirstName, MAX_STRING, stdin );

    size_t n = strlen( myfirstName );

    if ( n != 0 && myfirstName[n-1] == '\n' ) myfirstName[n-1] = '\0';

    return myfirstName;
}

and:

char*   getCompleteName (const char*    firstName,
                         const char*    lastName,
                         const char*    nickName,
                        )
{
    const char *format = "%s \"%s\"    %s";

    size_t n = strlen( firstName ) + strlen( lastName ) + 
               strlen( nickName ) + strlen( format );

    completeName = ( char * )malloc( n );

    snprintf( completeName, n, format, firstName,nickName,lastName);

    return completeName;
}

Define other functions in similar ways.

Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 1
    You should not cast the result of `malloc`. – John Bode May 23 '15 at 11:57
  • @John Bode Please next time do not repeat this stupidity after low-qualified programmers. And do not show me a reference at this forum where one such low-qualifier programmer repeats the same. – Vlad from Moscow May 23 '15 at 12:16
  • @VladfromMoscow: what stupidity? Casting the result of `malloc` is not only unnecessary, under C89 it can actually introduce a bug. Don't do it. – John Bode May 23 '15 at 12:39
  • @John Bode John, Let;s go forward and not backward.:) What is year now? It is without casting you can introduce a bug that will be difficult to find.:) There are only two stupid arguments do not use casting. The first one is that very old compilers do not warning about using an undeclared function and the second even more stupid argument that you may use malloc without casting. All these arguments are arguments of very low-quakified programmers. – Vlad from Moscow May 23 '15 at 12:46
  • @VladfromMoscow: what bug does *not* casting `malloc` introduce? `malloc`, `calloc`, and `realloc` all return `void *`, which may be assigned to other pointer type variables without need for a cast. It in *unnecessary*. It just adds visual clutter. It adds maintenance headaches if you change the type of the target. There is *no good reason* to do it. It's a holdover from pre-ANSI days. – John Bode May 23 '15 at 12:52
  • @John Bode For example consider two declarations int *p; int ( *q )[10]. Somewhere further in the program there is statement q = malloc( 10 * sizeof( int ) ); Now please answer can you say what is the type of q when you see the last statement? Can you be sure that it is a correct statement? – Vlad from Moscow May 23 '15 at 13:03
  • 1
    @VladfromMoscow: this is why you use `sizeof *q` instead of `sizeof (int)` - that way you get the right size regardless of type. Adding a cast is just one more opportunity to get it wrong. – John Bode May 23 '15 at 16:37
  • @John Bode The problem is that sizeof *q does not protect you from a bug because actually there shall be sizeof *p. Moreover expression sizeof *q or sizeof *p says nothing to the programmer what type has the pointer. You have to scroll the program text forward and backward that to find the declaration of the pointer that to know what memory is allocated for. – Vlad from Moscow May 23 '15 at 16:41
  • @John Bode In C++ such an assignment without casting is forbided. And it is a right decision because such an assignment is unsafe. – Vlad from Moscow May 23 '15 at 16:44
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/78612/discussion-between-john-bode-and-vlad-from-moscow). – John Bode May 23 '15 at 20:38
  • @John Bode Let discuss this some other time because it is rather late in Moscow and I am a bit tired. – Vlad from Moscow May 23 '15 at 20:50
  • @VladfromMoscow this topic is already discussed [here](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) where over 1000 people vote for not casting, and fewer than 100 vote for casting. – M.M May 25 '15 at 21:42
  • @Matt McNabb You have said nothing new. It is well-known that there are about 75% or even more imbeciles among people. The same is valid for programmers. – Vlad from Moscow May 26 '15 at 06:46
0

You should not use strlen() within malloc() to determine the number of bytes, you want to allocate into memory. Since, the character pointer variable, you are specifying within strlen() are "firstName,nickName,lastName", which are storing addresses of unknown location, which causes the given error. Therefore You should specify number of bytes, you want to allocate for different character pointer variable explicitly like this:

char* mylastName = (char*)malloc(150);

Here, 150 bytes will be allocated into memory and reference will be set char* mylastname .

kravi
  • 747
  • 1
  • 8
  • 13
0
char* myfirstName = (char*)malloc(strlen(firstName)+1);

In the above line, you're using firstName uninitialized. Strlen(firstName) will only work when firstName has some length which you passed to the function without giving it. Same goes to lastName and nickName.

Fahad Naeem
  • 515
  • 7
  • 15