0

This is a program I wrote (not including "string.h") which is meant to convert a string to upper case. It works with a single string - so far so good.

I run into trouble when I try to create an array of strings so I can test various strings in turn as part of a loop.

So, I don't understand why the program works when my string is declared as char test_string[] = "TEST"; but it does not work when I declare an array of pointers to strings.

This is the working single string version (followed by the non-working array of strings version):

#include <stdio.h>

void toAlpha(char*);
int str_len(char*);

int main()
{
    char test_string[] = "TEST";            /* string to test */
    char *pStr = NULL;                  /* pointer to string */

        pStr = test_string;
        toAlpha(pStr);
        printf("%s\n", pStr);


    return 0;
}


void toAlpha(char *arg)
{
    int i = 0;                  /* counter - original string*/
    int j = 0;                  /* counter - temp string */

    /* check each character in original and save alphabetic characters only */
    for ( i = 0; i < str_len(arg); i++ )
    {
        if( *(arg + i) >= 'a' && *(arg + i) <= 'z' )
            *(arg + j++) = *(arg + i);
        else
            if ( *(arg + i) >= 'A' && *(arg + i) <= 'Z' )
                *(arg + j++) = *(arg + i) - 'A' + 'a';
    }

    /* add a null character terminator */
    *(arg + j) = '\0';

}


int str_len(char *arg)
{
    /*return count of letters in a C string */
    int i = 0;
    if ( arg != NULL )
        while ( arg[i] != '\0' )
            i++;
    return i;
}

This is the non-working version with the failed attempt to use an array (it compiles but crashes at runtime):

#include <stdio.h>

void toAlpha(char*);
int str_len(char*);
void palindrome(char*);

int main()
{
    char *test_strings[1];                      /* strings to test */
    char *pStr = NULL;                          /* pointer to string */
    int i = 0;                                  /* loop counter */

    test_strings[0] = "TEST1";
    test_strings[1] = "TEST2";

    for (i = 0; i < 1; i++){
        pStr = test_strings[i];
        toAlpha(pStr);
        printf("%s\n", pStr);
    }

    return 0;
}


void toAlpha(char *arg)
{
    int i = 0;                  /* counter - original string*/
    int j = 0;                  /* counter - temp string */

    /* check each character in original and save alphabetic characters only */
    for ( i = 0; i < str_len(arg); i++ )
    {
        if( *(arg + i) >= 'a' && *(arg + i) <= 'z' )
            *(arg + j++) = *(arg + i);
        else
            if ( *(arg + i) >= 'A' && *(arg + i) <= 'Z' )
                *(arg + j++) = *(arg + i) - 'A' + 'a';
    }

    /* add a null character terminator */
    *(arg + j) = '\0';

}


int str_len(char *arg)
{
    /*return count of letters in a C string */
    int i = 0;
    if ( arg != NULL )
        while ( arg[i] != '\0' )
            i++;
    return i;
}
topsail
  • 2,186
  • 3
  • 17
  • 17
  • 2
    2 words `undefined behaviour` – user2485710 Feb 15 '14 at 22:28
  • http://stackoverflow.com/questions/8302290/why-does-char-cause-undefined-behaviour-while-char-doesnt or for more https://www.google.com/#q=undefined+behaviour+c+char* – user2485710 Feb 15 '14 at 22:28
  • 1
    There might be undefined behavior elsewhere, but this line: `test_strings[1] = "TEST2";` is certainly undefined behavior. – Cornstalks Feb 15 '14 at 22:28
  • 1
    2 more words `syntactical sugar` -- that is `char foo[] = "......";` as you do in your first example is a special kind of syntactical sugar. See the first SO link in the comments for the details explanation – Brandin Feb 15 '14 at 22:47
  • Thanks. I've been reading the links and finding some other posts about this here at stack overflow. Will comply! The syntactical sugar was sweet, at least for a little while. – topsail Feb 15 '14 at 23:31

3 Answers3

1

I found the error. You can't modify string literal. To fix this you need to substitute the following:

test_strings[0] = "TEST1";
test_strings[1] = "TEST2";

by:

test_strings[0] = (char *) malloc(sizeof(char) * (strlen("TEST1") + 1)); // +1 for the \n
test_strings[1] = (char *) malloc(sizeof(char) * (strlen("TEST2") + 1)); // +1 for the \n
strcpy(test_strings[0], "TEST1");
strcpy(test_strings[1], "TEST2");

Since you don't want to include string.h it seems that you need to implement the function strcpy. Also you need to include stdlib.h (because of malloc).

Luis Alves
  • 1,286
  • 12
  • 32
  • Okay. I'm convinced. Will give it a try. I think I'll break down and add string.h too - not writing any more of my own string functions tonight! – topsail Feb 15 '14 at 23:30
0

You have to include "stdio.h" for NULL macro and printf. The runtime problem is because you have an array of 1 element and you are assigning "TEST2" into the non-existing second position. I don't understand what you want to do in toAlpha().

#include <stdio.h>

// ...

int main()
{
    char *test_strings[2];                      /* strings to test */
    char *pStr = NULL;                          /* pointer to string */

    test_strings[0] = "TEST1";
    test_strings[1] = "TEST2";

    for (int i = 0; i < 2; ++i)
    {
        pStr = test_strings[i];
        toAlpha(pStr);
        printf("%s\n", pStr);
    }

    return 0;
}

// ...
  • I thought NULL was supposed to be defined in `stdlib.h`, see e.g. http://linux.die.net/man/3/malloc – Brandin Feb 15 '14 at 22:50
  • @Brandin: Your link does not specify where NULL is defined, stdlib.h could include stddef.h However, my answer is incorrect (edited), since it is not necessary to include stddef.h, because NULL is defined in both, stddef.h and stdio.h. See... http://en.cppreference.com/w/cpp/header/cstddef http://en.cppreference.com/w/cpp/header/cstdio http://en.cppreference.com/w/cpp/header/cstdlib – Fernando Pelliccioni Feb 15 '14 at 22:58
  • Thanks - added stdlib.h. It should have been there. – topsail Feb 15 '14 at 23:27
  • To be more precise, a pointer directly to C Standard (ISO/IEC 9899:201x - N1570). 7.19 Common definitions - Paragraph 3, and, 7.21 Input/output Paragraph 3 – Fernando Pelliccioni Feb 26 '14 at 18:51
0

Okay. Rewrote both programs. Hopefully better this time. But used string.h library in lieu of writing my own strcpy function. Though I didn't describe toAlpha properly. It's meant to remove any non-alphabetic characters, and to return the result as all lower-case letters. --Topsail

First program (single string):

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

    void toAlpha(char*);
    int str_len(char*);

    int main()
    {
        char test_string[100];              /* string to test */
        char *pStr = NULL;                  /* pointer to string */

            strcpy(test_string, "Test-A");
            pStr = test_string;
            toAlpha(pStr);
            printf("%s\n", pStr);


        return 0;
    }


    void toAlpha(char *arg)
    {
        int i = 0;                  /* counter - original string*/
        int j = 0;                  /* counter - temp string */

        /* check each character in original and save alphabetic characters only */
        for ( i = 0; i < str_len(arg); i++ )
        {
            if( *(arg + i) >= 'a' && *(arg + i) <= 'z' )
                *(arg + j++) = *(arg + i);
            else
                if ( *(arg + i) >= 'A' && *(arg + i) <= 'Z' )
                    *(arg + j++) = *(arg + i) - 'A' + 'a';
        }

        /* add a null character terminator */
        *(arg + j) = '\0';

    }


    int str_len(char *arg)
    {
        /*return count of letters in a C string */
        int i = 0;
        if ( arg != NULL )
            while ( arg[i] != '\0' )
                i++;
        return i;
    }

second program with array of strings:

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

    void toAlpha(char*);
    int str_len(char*);
    void palindrome(char*);

    int main()
    {
        char *test_strings[2];                      /* strings to test */
        char *pStr = NULL;                          /* pointer to string */
        int i = 0;                                  /* loop counter */

        test_strings[0] = (char *) malloc(sizeof(char) * (strlen("TEST-A") + 1));
        strcpy(test_strings[0], "TEST-A");
        test_strings[1] = (char *) malloc(sizeof(char) * (strlen("TEST-1") + 1));
        strcpy(test_strings[1], "TEST-B");


        for (i = 0; i < 2; i++){
            pStr = test_strings[i];
            toAlpha(pStr);
            printf("%s\n", pStr);
            free(pStr);
        }

        return 0;
    }


    void toAlpha(char *arg)
    {
        int i = 0;                  /* counter - original string*/
        int j = 0;                  /* counter - temp string */

        /* check each character in original and save alphabetic characters only */
        for ( i = 0; i < str_len(arg); i++ )
        {
            if( *(arg + i) >= 'a' && *(arg + i) <= 'z' )
                *(arg + j++) = *(arg + i);
            else
                if ( *(arg + i) >= 'A' && *(arg + i) <= 'Z' )
                    *(arg + j++) = *(arg + i) - 'A' + 'a';
        }

        /* add a null character terminator */
        *(arg + j) = '\0';

    }


    int str_len(char *arg)
    {
        /*return count of letters in a C string */
        int i = 0;
        if ( arg != NULL )
            while ( arg[i] != '\0' )
                i++;
        return i;
    }
topsail
  • 2,186
  • 3
  • 17
  • 17
  • Note: as it turns out implementing a string copy function is not difficult, as an exercise. See notes (and cautions) here: http://stackoverflow.com/questions/5695992/implementing-a-string-copy-function-in-c and also Kernighan and Ritchie 2nd edition section 5.5. – topsail Feb 16 '14 at 11:42