Search code examples
arraysccs50touppertolower

I'm having trouble converting argv to upper in C


I'm trying to convert a fixed size argv to upper and to lower but It either gives me segmentation fault or it just stores gibberish on the var. I've tried this:

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

int main(int argc, string argv[])
{
    string lower = "abcdefghijklmnopqrstuvwxyz";
    string upper = "abcdefghijklmnopqrstuvwxyz";

    for (int i = 0, n = 26; i < n; i++)
    {
        lower[i] = tolower(argv[1][i]);
        upper[i] = toupper(argv[1][i]);
    }
}

or:

string lower = "";
string upper = "";

//check if repeated chars or numbers
for (int i = 0, n = 26; i < n; i++)
{
    printf("%c\n",(char) argv[1][i]);
    printf("%c\n",(char) argv[1][i]);
    printf("%c\n",tolower(argv[1][i]));
    printf("%c\n",toupper(argv[1][i]));
    lower += tolower(argv[1][i]);
    upper += toupper(argv[1][i]);
}

The strangest part is that the printf's give the right values but they arent getting stored in lower or upper. What n00b thing am I doing here?


Solution

  • You cannot use += in C to append to a string.

    <cs50.h> defines string to be char *. Then string lower = ""; defines lower to be a char * and sets it to point to the first character of "". "" represents a null string, which is a string whose first and only character is the null (zero value) character, indicating the end of the string.

    When applied a pointer, += n attempts to advance the pointer by n elements of the type it points to. For example, if a pointer p is pointing to element 3 of an array, p += 4 will make it point to element 7.

    Since lower points to an element of an array with only one element, the null character, lower += tolower(argv[1][i]) attempts to make it point outside the array. The behavior is not defined by the C standard. (Except it could be in a C implementation in which tolower applied to that character yields a character with value 1. This would modify lower to point just beyond the last element in the array, which is a special position that is allowed for pointer arithmetic.)

    With string lower = "abcdefghijklmnopqrstuvwxyz";, you have more room to do the array arithmetic; some additions to lower will work. However, again, tolower(argv[1][i]) is likely too big to remain inside the array.

    Further, even if the pointer arithmetic works, lower += … only changes the pointer. It does not change the characters it points to.

    To make your code work, you need to allocate enough memory to hold the resulting string, including the null character, and you must set lower to point to that memory, and similarly for upper. The number of characters you need is strlen(argv[1][i]) + 1. If you have learned how to use malloc, you can use that. If you have a fixed assignment that guarantees that argv[1] will be exactly 26 characters, you can define lower and provide memory for it by declaring it with char lower[27];, and similarly for upper.

    Then, you must copy characters into that memory, which you can do with lower[i] = tolower(argv[1][i]);. When you are done copying characters into the array, you should write a null character at the end of it, to form a complete C string. (If you are not going to print the array as a string or otherwise use it as a string, you can omit this.)