Segmentation fault (core dumped)

Can someone please explain what that error message means? I'M tryin to use strcat() to add "0" to the left end of char *argv[1] I want it to do this only when the lenth of argv[1] can not evenly be divided by 3. So if I get 123 all is well, but if argv[1] is 1234 I need to append a "0" to the left. When I run the program rather than append the "0" it's giving me that error, and it's only doing that when the number is not a multiple of 3. Thanks.

This error message means that you are accessing an address of memory that is not reserved for your program. This usually occurs when you read or write at a location pointed to by an invalid pointer or beyond the valid memory that the pointer points to. For example, these are three potential segmentation fault cases:

int main() {

  int* p1;   // an uninitialized pointer is invalid.
  *p1 = 42;  // ERROR! Segmentation fault!

  int* p2 = NULL;  // the NULL location is a universally invalid value for a pointer.
  *p2 = 42;  // ERROR! Segmentation fault!

  int* p3 = new int[4];  // allocating an array of 4 integers. 
  p3[4] = 42;  // ERROR! Segmentation fault! (index 4 is beyond the valid memory)

  delete[] p3;

  return 0;
};

There are, of course, countless more situations, but they usually boil down to one of these cases.

I'M tryin to use strcat() to add "0" to the left end of char *argv[1]

You cannot do that. If you read the reference on strcat, you will see the following description of the "destination" parameter (first parameter to strcat):

"Pointer to the destination array, which should contain a C string, and be large enough to contain the concatenated resulting string."

If the destination memory location is not large enough for the total string, then you will get a segmentation fault (i.e., writing beyond the chunk of valid memory that "destination" points to).

I don't know exactly how your code is written, so I can't help you specifically, but I'm 100% sure that the above issue is what is causing your problems.

P.S.: Save yourself the trouble and use std::string:

#include <string>
#include <iostream>

int main(int argc, char** argv) {

  if(argc < 1) {
    std::cout << "Error! You must provide at least 1 argument!" << std::endl;
    return 1;
  };

  std::string s = argv[1];
  if(s.size() % 2 == 0) {
    s = "0" + s;     // <-- Here's the proper way to concatenate strings! (forget the evil strcat() function)
  };
  std::cout << "The argument is '" << s << "'." << std::endl;

  return 0;
};

The guy teaching me wants me to use c style strings and I was also told to stay away from classes completly until he's ready for me to move in that direction. Thanks though, I'M going to see if I can revise the code. I may post back here if I am still having trouble.

Okay, so now I'M having a error: incompatible types in assignment of ‘char’ to ‘char [13]’ problem. Does the char argv[1] come in as a c style string? If not, how can I convert or copy it into a C-style string?

Post your code. It's hard to speculate on what you are doing wrong without it.

Below is the code. The output is working fine if the number of digits in argv[1] is evenly divided my 3 but when it not evenly divided by 3 I'M getting the core dump error. What I'M trying to do here is add "0" to the left portion of argv[1] when the number of digits in argv[1] is not evenly divded by three.

123 -> GOOD, 1234 -> 001234, 12345 -> 012345

Also note that I can not use any kind of build in string class. Also, what I'M aksing is only one small problem in the overall of what I'M trying to do, this is not the assignment itself, so I'M not asking anyone to do my homework.

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include "functions.h"

int main(int argc, char *argv[200])
{
    int number = atoi(argv[1]);
    int numberOfGroups;
    int numberLength = strlen(argv[1]);

    std::cout << number << std::endl << numberLength << std::endl;

    numberOfGroups = get_groups(numberLength);

    std::cout << "the number of groups is " << numberOfGroups << std::endl;

    while ( numberLength / 3 != numberOfGroups || numberLength < 3 )
    {
        strcat("0", argv[1]);
    }
    std::cout << "The number is " << argv[1] << std::endl;

    return 0;
}

// FUNCTIONS

int get_groups(int length)
{
    int groups = 0;

    if ( length <= 3 )
    {
        groups = 1;
    }
    else if (length % 3 != 0 && length)
    {
        groups = (length / 3) + 1;
    }
    else if (length % 3 == 0 && length)
    {
        groups = length / 3;
    }
    return groups;
}

I was also told to stay away from classes completly until he's ready for me to move in that direction.

That sounds like the kind of thing a teacher who's only a step or two ahead of you in the learning process would say to avoid being embarrassed.

Why would a teacher be asking the question? I don't get it. I'M not in School, I'M being taught by a programmer/Linux admin who's been willing to give me his time.

First of all, your loop is infinite:

while ( numberLength / 3 != numberOfGroups || numberLength < 3 )
{
    strcat("0", argv[1]);
}

Because the values in the expression ( numberLength / 3 != numberOfGroups || numberLength < 3 ) are all constant throughout the loop iteration, so if it starts (evaluates to true), it will never end (the condition will always evaluate to true). A simpler way to check if the length is not an even factor of three is (strlen(argv[1]) % 3) (if non-zero, it means it is not an even factor of three).

Second, for the problematic expression, strcat("0", argv[1]);, if you read the reference page for strcat(), you will see that the first parameter (i.e., "0") is supposed to be the destination, not the second argument (as you seem to think). And, the destination must be large enough to hold the entire destination string, which is clearly not the case here because the string "0" is only big enough to hold one character and the null-terminating character.

I think that the method you are using is beyond repair, you must change your strategy. First, you will need to allocate an array of characters big enough to hold argv[1] + leading zeros + the null-terminating character. The number of characters in the final string can be calculated as the first 3-even number above or equal to the length of argv[1]. This can be computed as:

int old_str_length = strlen(argv[1]);
int new_str_length = ((old_str_length + 2) / 3) * 3;

In other words, if old_str_length is an 3-even number, say 6, then new_str_length will be equal to ((6 + 2) / 3) * 3 == (8 / 3) * 3 == 2 * 3 == 6. If the old_str_length is equal to 7, then you get (9 / 3) * 3 == 3 * 3 == 9. If the old_str_length is equal to 8, then you get (10 / 3) * 3 == 3 * 3 == 9. And so on.

Once you have the length of the final string, you can allocate an array of characters big enough for that and the null-terminating character:

char* new_str = new char[ new_str_length + 1 ];

And then, you can add the required number of zeros, a simple method is this:

memset(new_str, '0', old_str_length % 3);
new_str[old_str_length % 3] = '\0';  // null-terminating character.

And then, because you have the required amount of space in your destination array, you can do a strcat call:

strcat(new_str, argv[1]);

And then, print the result:

std::cout << new_str << std::endl;

And, after you are done using the new_str array, you must delete it:

delete[] new_str;
commented: Nice that you took the time to explain it step-by-step :) +13

Wow, I'M really dizzy now. Thanks. The one larg mental block I have here is that I do not understand the heap. I know that it exist and that the syntax for placing variables on the heap is the new key word and I only know that because someone told me or I read, hey, there's a place in memory called the heap and you can access it using new. Other than that I have no idea when, how, or why I would need to do such a thing. Thanks again for your help I'M going to start looking it over and trying it out on my program.

The more formal name for the "heap" is actually "freestore memory". In short, all the memory consumed by local variables is on what is called the "stack", which grows (by stacking more and more variables) as you declare more local variables and as you call functions that have local variables in them. Each function, with all its local variables (including function parameters), consume a certain amount of memory, but that memory is fixed at compile-time (i.e., the compiler generates static code that allocates those variables on the stack). If you need a certain amount of memory but it is unknown, at compile-time, how much memory you will need (e.g., like in the example, you don't know how many characters you will need until you have the argv[1] string, which is obtained when running the program), then, you need to allocate that memory dynamically (at run-time). The heap or freestore memory is there for that purpose. And yes, you allocate such memory by using the new operator, and you deallocate that memory with the delete operator (once you no longer need it).

The most basic example is this:

#include <iostream>

int main() {
  int run_time_count = 0;
  std::cout << "Please enter the size of the array: ";
  std::cin >> run_time_count;

  // allocate an array of the specified length from the heap:
  int* p_array = new int[ run_time_count ];

  // at this point, p_array is a pointer to the first element of 
  // the newly allocated array.

  // fill the array with values (0,1,2,3...):
  for(int i = 0; i < run_time_count; ++i)
    p_array[i] = i;

  // print out the values in the array:
  for(int i = 0; i < run_time_count; ++i)
    std::cout << p_array[i] << std::endl;

  // deallocate the array, since it is no longer needed at this point:
  delete[] p_array;

  return 0;
};

This is basically all there is to it. You can ask for some memory to be given to you, then use it as you wish (remaining within the bounds of it, otherwise you get a segmentation fault (or Access Violation in Windows)), and finally, give the memory back to the system once you no longer need it. Most of the trouble arises either when you forget to deallocate what you have allocated (this is called a "memory leak") or when you have to copy, transfer, or renew (grow / shrink) the memory block, because you have to be careful about the sequence of the operations (e.g., first allocate the new block of memory, then do some copying / concatenation, then delete the old block of memory, and then update the pointer). But, in principle, it's very easy to understand.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.