Hello.

I'm writing a program in C that should ask for a line of input, and extract the process name and parameters. This doesn't have to be totally bulletproof at this point. An example input could be:
"Hello these are parameters". On this example "Hello" would be the string i want as process name, and the other words are parameters. I'm using getline (http://linuxmanpages.com/man3/getline.3.php) to get input from stdin.
I don't allocate more memory for the individual words but instead store pointers of the main string, and replace spaces with null characters. The program worked before, but after I made some changes I get this segmentation error which I can not get rid of. (Neither can i find what changes were made since the working version) I also tried allocating memory for the "buffer" variable in the acquireInput function myself instead of letting getline do it, but the result was the same.

The part of the program where my code crashes looks as follows:

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

struct Command
{
    char* process;                  //First word contained in buffer.
    char** parameters;              //Array of memory addresses contained in buffer that are the beginning of parameters. (Dynamically allocated)
    unsigned int parameterAmount;   //Variable that holds that amount of parameters.
};


char* acquireInput(struct Command *input, unsigned int *parameterAmount);
int isWhitespace(char character);
void extractWords(char *process, char *parameters[], unsigned int *parameterAmount, char *buffer, unsigned int bufferSize);

int main(int argc, char *argv[])
{
    char *buffer = NULL;            //Buffer that will contain the entire inputstring. (Dynamically allocated)
    struct Command input = { NULL, NULL, 0 };

  do
    {
        //Pointers will get overwritten each iteration.
        //Free the allocated memory.
        free(buffer);
        free(input.parameters);
        buffer = acquireInput(&input, &input.parameterAmount);
    }
    while(1); //temporary

    printf("\n");
    return 0;
}

char* acquireInput(struct Command *input, unsigned int *parameterAmount)
{
    char *buffer = NULL;
    size_t bufferSize = 0;
    unsigned int charactersRead = 0;

 printf("INPUT: ");
    charactersRead = getline(&buffer, &bufferSize, stdin); //crash happens at this point.

input->parameters = (char**) malloc(((charactersRead / 2) + 1) * sizeof(char*));
    extractWords(input->process, input->parameters, parameterAmount, buffer, charactersRead + 1);

    return buffer;
}

void extractWords(char *process, char *parameters[], unsigned int *parameterAmount, char *buffer, unsigned int bufferSize)
//TODO: Words between quotes are 1 word, even if there's a whitespace between them.
{
    int i = 0;
    *parameterAmount = 0;
    *process = 0;

    //As long as the string-terminating NULL character hasn't been reached.
    while(i < bufferSize - 1)
    {
        //move to the next word.
        while (isWhitespace(buffer[i])) i++;

        //Add the word to the words array if it's not the final NULL character..
        if (buffer[i] != '\0')
        {
            if (*parameterAmount == 0)
                process = buffer + i;
            else
                parameters[(*parameterAmount)++] = buffer + i;
        }

        //Move to the end of the word and mark it with a null character.
        while (!isWhitespace(buffer[i]) && buffer[i] != '\0') i++;

        //if the end of this word isn't the NULL character, place one move 1 character further.
        if (buffer[i] != '\0')
            buffer[i++] = '\0';
    }
}

int isWhitespace(char character)
{
    return (character == '\n' || character == '\t' || character == ' ');
}

I'm running Fedora 12 (Constantine) as a Virtual Machine in VMWare, using Code::Blocks as IDE and GNU GCC as compiler with the -Wall option enabled.
I hope anyone could give me some feedback on what could cause this problem.

Thanks in advance,
Gonbe.

-edit-
I forgot to add the output of the program (though it's not exactly informative):

INPUT: 
Segmentation fault (core dumped)

This is when I hit enter during the input-moment. (The result is the same when entering text)

Are you certain that the crash occurs at the getline call? I'm not on a *nix system, so I can't run your code, but that call looks okay given this and what I see in the code. Did you discover the crash point by stepping through with a debugger? If not, consider adding more flushed outputs to verify whether the crash occurs there or later.

[edit]In fact, isn't the following guaranteed to write to a null pointer given your example?

void extractWords(char *process, char *parameters[], unsigned int *parameterAmount, char *buffer, unsigned int bufferSize)
//TODO: Words between quotes are 1 word, even if there's a whitespace between them.
{
   int i = 0;
   *parameterAmount = 0;
   *process = 0;

Edited 6 Years Ago by Dave Sinkula: n/a

Comments
Helped me in a clear way.

Are you certain that the crash occurs at the getline call? I'm not on a *nix system, so I can't run your code, but that call looks okay given this and what I see in the code. Did you discover the crash point by stepping through with a debugger? If not, consider adding more flushed outputs to verify whether the crash occurs there or later.

I added a printf statement before the getline statement, and another one after it. On execution the printf statement that came before getline was executed correctly, and then the segmentation error showed up before the printf statement that came after getline was displayed.

[edit]In fact, isn't the following guaranteed to write to a null pointer given your example?

void extractWords(char *process, char *parameters[], unsigned int *parameterAmount, char *buffer, unsigned int bufferSize)
//TODO: Words between quotes are 1 word, even if there's a whitespace between them.
{
   int i = 0;
   *parameterAmount = 0;
   *process = 0;

This was indeed the error! I've modified this (process should have been a pointer to a pointer as I wanted to modify the address itself) and now the code works. (aside from some other bugs that i fixed now aswell) I still do not know why the program would crash at the getline and not at this specific asignment though.

Edited 6 Years Ago by Gonbe: n/a

If not, consider adding more flushed outputs to verify whether the crash occurs there or later.

I added a printf statement before the getline statement, and another one after it. On execution the printf statement that came before getline was executed correctly, and then the segmentation error showed up before the printf statement that came after getline was displayed.

Just so that I'm clear, and for future debugging, by "flushed output" I meant adding the following after a debugging printf (or puts , etc.) to ensure it gets printed.

printf("Got here\n");
fflush(stdout);

http://c-faq.com/stdio/fflush.html

This was indeed the error! I've modified this (process should have been a pointer to a pointer as I wanted to modify the address itself) and now the code works. (aside from some other bugs that i fixed now aswell) I still do not know why the program would crash at the getline and not at this specific asignment though.

I'm glad you found your problem.

But I don't think it crashed where you think it did. I think it crashed at the null pointer access, but that your output was buffered and you didn't see your debugging display text. Keep in mind flushing the output as I mentioned for future debugging -- it only makes life more difficult when you have to debug your debugging instead of just suspect code!

Also, stepping through with a debugger (which I had done using after writing my own version of getline for your example [which itself could be problematic I realize]) might take you past the line where you think it crashed.

This article has been dead for over six months. Start a new discussion instead.