1

I keep getting a segmentation error when I try to add a character to the string test. I have tried multiple iterations and can't figure out why I get the error. I tried having the test set to \0. I can't figure out how I am accessing outside test.

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

#define _XOPEN_SOURCE
#include <unistd.h>
#include <crypt.h>

//this intializes the argument count and argument vector
int main(int argc, string argv[]) {
    //this makes sure it is a string
    if (argv[1] != NULL) {
        //this makes sure that the user typed 2 arguments, 
        //  the second being the keyword
        if (argc != 2) {
            printf("no hash inputed\n");
            return 1;
        }

        //main program once the keyword has been verified
        int h_len = strlen(argv[1]); 
        string hash = argv[1];
        string test = "A";
        int p_len = 0;
        printf("H len is %i and P len is %i\n", h_len, p_len);
        printf("%s and test: %s\n", hash, test);

        //this will iterate through the 1st space and test the charachters
        for (int j = 0; j < 4; j++) {

            //iterates through the characters that can be used in the  password
            //for (int i = A; i < z; i++)
            //for (char ch = 'A' ; ch <= 'z' ; ch == 'Z' ? ch = 'a' : ++ch )
            for (char i = 'A'; i <= 'z'; i++) {
                //this skips the ASCII inbetween Z and a
                if (i > 'Z' && i < 'a') {
                    i = 'a';
                }
                printf("%c", i); 
                //test[j] = test[j] + (char)i;
                test = strncat(test, &i, 1);
                printf("  test is %s\n", test);
                ...
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 3
    You need to check `argc` _before_ you access `argv[1]`. – ad absurdum Jul 13 '17 at 14:00
  • 1
    You have allocated one character for test.. and then tried to append to it. – Spaceghost Jul 13 '17 at 14:01
  • 1
    The code has `//this makes sure that the user typed 2 arguments`. These will be in `argv[1]` and `argv[2]` unless you enclose them in quotes such as `"one two"`, when they will be passed to the same argument. But the code has `if ( argc != 2)` which is testing for only one **user** argument - the first is the executable's name. – Weather Vane Jul 13 '17 at 14:05

4 Answers4

4

In this declaration

string test = "A";

there is declared the pointer test to the string literal "A". You may not change string literals.

According to the C Standard (6.4.5 String literals)

7 It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined

However in this statement

test = strncat(test, &i,1);

there is an attempt to modify the string literal pointed to by the pointer test.

You should declare a character array that has enough space to store additional characters.

Moreover if you are using the function strncat to copy n characters from the source string you should reserve memory in the destination array for n + 1 characters because the function always appends the terminating zero.

That is (The C Standard, 7.23.3.2 The strncat function, footnote 302)

302) Thus, the maximum number of characters that can end up in the array pointed to by s1 is strlen(s1)+n+1.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 1
    @chux To make it clear I appended the answer with a footnote from the Standard.:) – Vlad from Moscow Jul 13 '17 at 15:17
  • That footnote not only added clarity here, but caused me to review various posts I've made over the years obliging 3 updates - sigh. – chux - Reinstate Monica Jul 13 '17 at 15:59
  • 1
    @chux: yes, `strncat()` is much more palatable than `strncpy()`. It actually a decent way to implement a truncating string copy: `char dest[10] = ""; strncat(dest, src, sizeof(dest) - 1);` – chqrlie Jul 13 '17 at 20:14
  • True, `char dest[N]; dest[0] = 0; strncat(dest, src, sizeof dest - 1);` has minor benefit of 1) less unneeded initialization with large N 2) Explicit `dest[0] = '\0';` useful for learners. – chux - Reinstate Monica Jul 13 '17 at 20:19
1

Note that in this horrible cs50, string is defined as char *, so string test = "A"; is equivalent to char *test = "A"; which will make test point to a constant string of length 1 plus a null!

So even if it would be long enough to concatenate anything, you can't because it is read-only, and even if it was not read-only, you can't because it is not long enough.

Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
0

You have a string with one character in it (test="A") so it has a length of 2 (A + null char) and are trying to append other characters to it, so it WILL access outside of test.

lostbard
  • 5,065
  • 1
  • 15
  • 17
  • 1
    Incomplete answer. `test` points to a string literal: attempting to modify it has undefined behavior anyway. – chqrlie Jul 13 '17 at 14:52
-1

everything is wrong here

you cant strcat char * and the address of the char as you never know if there is zero after that character. Your string is too short to accomodate anything longer than one character string. Next - you try to do something with RO memory as your test points to the string literal.

Buy a good book about C

0___________
  • 60,014
  • 4
  • 34
  • 74
  • `strncat` works if you pass 1 doesn't need null-terminator. And the string is too short but mostly it's a pointer not an array so segfault whatever the size – Jean-François Fabre Jul 13 '17 at 14:03
  • yeah I thought that is strcat – 0___________ Jul 13 '17 at 14:04
  • 1
    @Jean-FrançoisFabre: more precisely, it ihas undefined behavior because it points to a *string literal*. – chqrlie Jul 13 '17 at 14:51
  • Both are UB's so actually it does not matter. I can't say which UB is more bad. Both have to be corrected. – 0___________ Jul 13 '17 at 14:55
  • I was referring to the *it's a pointer not an array* part of JF's comment, which seems irrelevant. The OP's code has multiple counts of UB, which of course do not cancel each other ;-) – chqrlie Jul 13 '17 at 15:05