-1

I'm trying to declare an array of char dynamically, what I need to do is adding the newest character to the string which works fine, the problem is that when I try to print it out, at the beginning of the string there are some unknown characters.

char add[2];
char str2[200];
char c;
int temp = -1;
int num = 0;
char *str3;
str3 = malloc( (size_t)count ); //str3 = malloc(sizeof(char)) not working
while((c= getch()) !='\r')
{
    for (int i = 0;i<200;i++)
    {
        if (str2[i] =='\0')
        {
            num = i;
            break;
        }
    }
    //printf("Num: %d\n",num);

    if ((temp == -32) || (temp == 0))
    {
    }
    else
    {
        if(isalnum((char)c) == 0)
        {
            if((c == '\'') || (c == -118) || (c == -115) || (c == -107) || (c == -123) || (c == -105)|| (c == 32))
            {
                realloc(str3,sizeof(char)+2);
                printf("true: %c\n",c);
                //realloc(str2,sizeof(char)+1);
                add[1] = '\0';
                add[0] = c;
                strcat(str3,add);
                strcat(str2,add);
                printf("%s\n",str2);
                printf("%s\n",str3);
            }
            else if (c == 8)
            {
                printf("Deleting something...\n");
            }
        }
        else
        {
            realloc(str3,sizeof(char)+2);
            printf("true: %c\n",c);
            //realloc(str2,sizeof(char)+1);
            add[1] = '\0';
            add[0] = c;
            strcat(str3,add);
            strcat(str2,add);
            printf("%s\n",str2);
            printf("%s\n",str3);
        }
    }
    printf("ASCII Code: %d\n",c);
    temp = c;
}
GeneNight
  • 35
  • 6
  • Please note that you have some typos in your post. Also, you don't need to cast the output of malloc. – myradio Jun 13 '18 at 13:39
  • See: https://stackoverflow.com/questions/8164000/how-to-dynamically-allocate-memory-space-for-a-string-and-get-that-string-from-u – Jonny Schubert Jun 13 '18 at 13:40
  • I saw you corrected the typos. I don't understand what you want to do. Can you post the actual code where the problem is? In your first two malloc's you are getting memory blocks of the size of 1 char only, and I assume that is not what you want. In the third malloc, you actually reserve a bigger block of memory, that might be the reason why whatever you are doing works on that case. – myradio Jun 13 '18 at 13:41
  • 1
    Show us the [mcve]. – Eugene Sh. Jun 13 '18 at 13:42
  • @Lundin Not to mention another one about *strings*. – Iharob Al Asimi Jun 13 '18 at 13:50
  • I just edited my post putting the code that works, I commented the other malloc declaration which doesnt perfectly works. – GeneNight Jun 13 '18 at 13:50
  • You should not change the content of the question that heavily, by removing the problem you have from the question and replacing it with the solution all answers get wrong, because they do reference a now non existent problem. Please rollback to the last revision. – Kami Kaze Jun 13 '18 at 14:04

3 Answers3

3

To get some memory to your string, you have to tell malloc how many bytes of memory you want. sizeof(char) returns 1, therefore, you'll only have 1 byte. In C, strings are terminated by the NULL byte (\0), and printf and others will print until they find that NULL terminator.

If you do something like this:

char *str = malloc(1);
*str = 'a';
printf("%s", str);

You will probably get a very strange output, since you have no NULL terminator.

When you use the unsigned x; str = malloc(x);, it's actually undefined how many bytes you have, since that x variable is not initialized.

Since your question is very unclear, what I can tell you (from what I think you're asking) is how to actually get space for a string of 63 characters plus the NULL terminating byte.

char *str = malloc(64);
strcpy(str, "Stack Overflow");
printf("%s", str);

That will do it.

Also note that the memory block returned by malloc will not be zeroed, therefore you can't possibly know what's in it (that could be the reason you're getting garbage when you're printing).

I recommend you read about memory allocation in a good C book or in Wikipedia...


After your edit and "MCVE"

I made some edits to what I think it is you want. The modifications are explained in the comments of the source. Let me know if you have any doubts.

#include <stdio.h>  /* printf */
#include <stdlib.h> /* malloc, free, realloc */
#include <string.h> /* strcat */
#include <ctype.h>  /* isalnum */
#include <conio.h>  /* getch */

int main(void)
{
    char add[2];
    char str2[200];
    char c;
    int temp = -1;
    int num = 0;
    char *str3;

    /* I just think 'count' is an int, since you didn't put it in the code, 
     * I also deduced that @count will be used as the length of @str3 
     */
    int count;

    /* Here, count is not initialized, so you MUST initialize it in order 
     * to call malloc with it! Since it seems you want to add character by
     * character using realloc, then we just malloc() 2 bytes - 1 for a 
     * character and one for the NULL terminator.
     */
    count = 2;
    str3 = malloc(count);

    /* You will be using @strcat to append strings to @str3, so you need
     * to put a NULL terminator in it, because strcat will look for that
     * NULL byte to find where it should append
     */
    *str3 = 0x0;

    while((c = getch()) != '\r') {
        for (int i = 0;i < 200; i++) {
            if (str2[i] =='\0') {
                num = i;
                break;
            }
        }

        if ((temp == -32) || (temp == 0)) {
            /* empty */ 
        } else {
            if(isalnum((char)c) == 0)
            {
                if((c == '\'') || (c == -118) || (c == -115) || (c == -107) || (c == -123) || (c == -105)|| (c == 32))
                {
                    /* this is not the optimal way of using realloc, because
                     * you should first check for errors, but will do for
                     * this example.
                     * You must assign the returned value of realloc to str3. 
                     *
                     * Also, since @count contains the length
                     * of @str3, you need to increment it.
                     */
                    str3 = realloc(str3, ++count);
                    printf("true: %c\n",c);
                    add[1] = '\0';
                    add[0] = c;
                    strcat(str3,add);
                    strcat(str2,add);
                    printf("str2: %s\n",str2);
                    printf("str3: %s\n",str3);
                } else if (c == 8) {
                    printf("Deleting something...\n");
                }
            } else {
                /* see notes above on realloc */
                str3 = realloc(str3, ++count);
                printf("true: %c\n",c);
                add[1] = '\0';
                add[0] = c;
                strcat(str3,add);
                strcat(str2,add);
                printf("str2: %s\n",str2);
                printf("str3: %s\n",str3);
            }
        }
        printf("ASCII Code: %d\n",c);
        temp = c;
    }
    return 0;
}
Enzo Ferber
  • 3,029
  • 1
  • 14
  • 24
  • Thank you man, really, just one quesiton, what does this assignament do? *str3 = 0x0; – GeneNight Jun 13 '18 at 14:13
  • @GeneNight That `*str3 = 0x0` makes the first byte of `str3` a `NULL` byte (the indicator of end of string). Since you will be using `strcat`, you need this (because malloc most likely will return a chunk of memory that contains garbage in it). It is similar to do `str3[0] = 0x0` or `str3[0] = '\0'`. – Enzo Ferber Jun 13 '18 at 14:14
  • That really explains everything, thank you very much the answers, I have no more doubts. – GeneNight Jun 13 '18 at 14:19
0

In the first two cases, you are only allocating enough space for a single char. If you attempt to write more than one to that block of memory, you'll write past the end of the memory that was allocated for you. Doing so invokes undefined behavior, which in this case manifests as printing strange characters.

In the third case, you allocate x bytes of memory, however x is uninitialized and has an indeterminate value. Reading an indeterminate value is also undefined behavior. In this case it happens to work because the indeterminate value happens to be a valid value and is large enough to hold the string you want, however you can't depend on that behavior.

You need to allocate a byte for every character that you'll need, plus 1 for the terminating null byte that ends a string in C.

dbush
  • 205,898
  • 23
  • 218
  • 273
0

Note that the first allocation, this one

str = malloc(sizeof(char));

is exactly equivalent to1

str = malloc(1);

so you don't have room except for one character which is a problem, because it only represents an empty string.

If you allocate this much space you will very likely access memory out of the allocated space, causing undefined and unpredictable behavior. You need to understand what a string in is,

  • A string in is a sequence of non-null characters followed by a null character, so for a string with N characters you need N + 1 array elements (for ascii this equals bytes)

According to that definition of string if you wanted to store the string "Hello" you would need at least the following code

char *str = malloc(6);
if (str != NULL) {
    str[0] = 'H';
    str[1] = 'e';
    str[2] = 'l';
    str[3] = 'l';
    str[4] = 'o';
    str[5] = '\0'; // Or equivalently str[5] = 0;
}

as you can see, the last character being '\0' or 0which is the same — is very important.

All the functions in the standard library of which expect a string parameter expect that there is the null terminator. For instance strlen() will count characters until it reaches the '\0', if it's not there then you can't predict where it is going to stop counting, this causing undefined behavior.


1sizeof(char) is as defined by the standard always equal to one.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97