# **char** limitations



## Concorde (Jul 28, 2005)

I am a low level computer programmer. On a scale of 1-10, I would say I am a 3 maybe a 4. I do understand most of what is going on in a given program. This is just so you don't respond to this like you are talking to a beginner or a 4 year old.

I am making quite a few programs in C++ right now, most of which are for a class(I'm in college). I understand how to affect character arrays in many ways, but I do not understand why "char equation[sizeplus];" is not a valid line. I do know that it has something to do with "sizeplus". I was taught that if you give a character array a size, it has to be 2 or more to allow for the basic input and then the null terminator.

I have used the only ways I know to set a standard size greater than or equal to 2 in an array so that provided I know the base size of an input or have a lot of locations using the array, I need only modify one space to increase or decrease the size of the array.

#define sizeplus 1000; or int sizeplus = 1000;
char equation[sizeplus + 2];

In this instance, I can later affect sizeplus through other inputs and still keep the array of size 2 or greater.


----------



## aewarnick (Sep 3, 2002)

I don't know who taught you the size needs to be at least 2. A char array is just like any other array in that you can create 1 or more elements.

char p[1]; *p= 0; or p[0]=0;
Is perfectly valid.

I'm not really sure what you're asking either.


----------



## IMM (Feb 1, 2002)

I'm not sure what he's asking either - but I think he's trying to modify an allocation size dynamically on something which has a size determined at compile time ?


----------



## Concorde (Jul 28, 2005)

aewarnick said:


> I don't know who taught you the size needs to be at least 2. A char array is just like any other array in that you can create 1 or more elements.
> 
> char p[1]; *p= 0; or p[0]=0;
> Is perfectly valid.
> ...


I was taught that if you set an initial size it has to be 2 or more for an initial character in p[0] and then a null terminator set in p[1](therefore a size of 2). If you don't or only need just a single char input then you could just use char p;.

I probably put too much into my explanation and that confused you. What I am asking is why the compiler will not allow me do use a predetermined size for the array p[size];, but instead forces me to use p[10]; or p[100];.

I would like to know why that is because I am starting to use many arrays in my programs and I know that I can make multiple dimension arrays, but I confuse myself with those sometimes, so this seems easier.

What I would like to do is:
...
#define size 50;
...
int main()
...
char p[size];
...
for (int i=0;i<size;i++)
...

If any of this confuses you, message me and I can get you some of my actual used code to show both what I would like to do, and what I have to do.


----------



## coderitr (Oct 12, 2003)

The array size must be a constant at compile-time. The #define should work. The int won't. I read a lengthy article on variable length arrays (VLA's) a couple of years ago but would be hard-pressed to find it now. BTW, I had a coding error the other day where I had defined a char foo[0] and the compiler didn't stop on it. Not very useful but not a compile error either.


----------



## Concorde (Jul 28, 2005)

Personally - I think the guys who create the compilers are stupid. Did you know that you can open a file and not close it and the compiler doesn't care. If you don't close the file, it acts as if it was never created in the first place. Yet, it doesn't trust that I know the array size is valid.
Also, if I knew how to, there are so many things I would change to make it easier on the user when creating the source file. One thing I would change - if (b>c && b<a) to if (c<b<a &&). I believe that is looks a little more neat than the first. With that changed, you could easily test many variables against eachother without a lot of && taking up space - if (a>b>c>d>e &&).


----------



## coderitr (Oct 12, 2003)

Concorde said:


> Personally - I think the guys who create the compilers are stupid. Did you know that you can open a file and not close it and the compiler doesn't care. If you don't close the file, it acts as if it was never created in the first place.


That's because the compiler is checking syntax, not logic errors. The file is not written until the buffer is flushed and that usually happens at a file system level when you close the file. Personally, I'd get a little more experience under my belt before I started calling people who know a lot more than I do "stupid." But that's just me.



Concorde said:


> Also, if I knew how to, there are so many things I would change to make it easier on the user when creating the source file. One thing I would change - if (b>c && b<a) to if (c<b<a &&). I believe that is looks a little more neat than the first. With that changed, you could easily test many variables against eachother without a lot of && taking up space - if (a>b>c>d>e &&).


More concise, yes, but also more difficult to read. Maintainability is a concept you should familiarize yourself with. I've been so frustrated so many times over spaghetti code I inherited from someone else that is nearly impossible to follow.


----------



## brendandonhu (Jul 8, 2002)

Concorde said:


> Personally - I think the guys who create the compilers are stupid. Did you know that you can open a file and not close it and the compiler doesn't care. If you don't close the file, it acts as if it was never created in the first place.


None of these actions are part of C++. The compiler does not provide any access to files. This is all provided by system APIs and header files. The compiler can't decide when the OS decides to write to a file.



> Yet, it doesn't trust that I know the array size is valid.


It can't assign memory if it doesn't know the size of the variable.


----------



## jiml8 (Jul 3, 2005)

brendandonhu said:


> It can't assign memory if it doesn't know the size of the variable.


The #define should work.


----------



## brendandonhu (Jul 8, 2002)

Agreed.


----------



## aewarnick (Sep 3, 2002)

Are you looking to dynamically create any sized arrays? Is so, you use new/delete or malloc/free for that:
int sz= 9876328;
char* c=new char[sz];
or
char* c=(char*)malloc(sz*sizeof(char)); //sizeof(char) isn't necessary here.


----------



## GCDude (Apr 1, 2005)

yep, but just remember to delete(using new) or free(malloc) after you have finished with them.

However if you are using c++ why not use basic_string then you dont have to bother with any length worries.


----------



## Concorde (Jul 28, 2005)

GCDude said:


> yep, but just remember to delete(using new) or free(malloc) after you have finished with them.
> 
> However if you are using c++ why not use basic_string then you dont have to bother with any length worries.


Can you take a cin input into a string? I haven't done much with strings in c++ except for using them to return from a function.


----------



## Shadow2531 (Apr 30, 2001)

^^

string s;
getline(cin,s);


----------



## Shadow2531 (Apr 30, 2001)

I can't take credit for this as it's an adapted form of someone else's suggestion for a question I had on another forum about how to use realloc properly, but here's an example of dynamically resizing an array so you don't have to know the initial size. (using c-methods in c++).


```
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

int getline(FILE* stream, char** pstr) {
    for (size_t i = 0; ; i++) {
        char c = fgetc(stream);
        if (c == '\n') {
            break;
        }
        if ( NULL == ( *pstr = (char*)realloc(*pstr, i + 2) ) ) {
            free(*pstr);
            *pstr = NULL;
            return 1;
        }
        (*pstr)[i] = c;
        (*pstr)[i + 1] = 0;
    }
    fflush(stdin);
    return 0;
}

int main() {
    char* str = NULL;
    printf("\nEnter a string\n\n");
    if ( 1 == getline(stdin,&str) || str == NULL ) {
        return 1;
    }
    printf("\n%s\n", str);
    if ( 0 == str[ strlen(str) ] ) {
        printf("\nnull-terminated\n");
    }
    free(str);
    str = NULL;
}
```
I made it behave similar to the getline function for std::string, but it keeps the null character; since we're dealing with an array. Also, it returns an int for error handling instead of using exceptions.

That is a convience function; not an efficient one.

Edit:

Here's the same thing, but with this one, if you just press enter, instead of just exiting, it makes the string have a size of 1 with a null character set similar to how getline() for strings would do. If you have a char* that is not NULL, the function will wipe out the memory assoicated with it and set it to NULL similar to how getline for strings would do. The only requirement is that you don't pass it a reference to a non-null non-dynamic char*.


```
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

int getline(FILE* stream, char** s) {
    if (*s != NULL) {
        free(*s);
        *s = NULL;
    }
    for (size_t i = 0; ; i++) {
        char c = fgetc(stream);
        if (c == '\n') {
            break;
        }
        if ( NULL == ( *s = (char*)realloc(*s, i + 2) ) ) {
            free(*s);
            *s = NULL;
            return 1;
        }
        (*s)[i] = c;
        (*s)[i + 1] = 0;
    }
    fflush(stdin);
    if (*s == NULL) {
        if ( NULL == ( *s = (char*)realloc(*s,1) ) ) {
            free(*s);
            *s = NULL;
            return 1;
        }
        (*s)[0] = 0;
    }
    return 0;
}

int main() {
    char* str = NULL;
    printf("\nEnter a string\n\n");
    if ( 1 == getline(stdin,&str) ) {
        return 1;
    }
    printf("\n%s\n", str);
    if ( str[ strlen(str) ] == 0 ) {
        printf("\nnull-terminated\n");
    }
    free(str);
    str = NULL;
}
```
If you want to be able to pass to the function, a reference to a dynamic char* AND pass it a reference to non-null, non-dynamic char*, you need to add a boolean argument so the function knows if it should call free if *s is not null.

example.


```
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

int getline(FILE* stream, char** s, const bool& dynamic) {
    if (*s != NULL) {
        if (dynamic) {
            free(*s);
        }
        *s = NULL;
    }
    for (size_t i = 0; ; i++) {
        char c = fgetc(stream);
        if (c == '\n') {
            break;
        }
        if ( NULL == ( *s = (char*)realloc(*s, i + 2) ) ) {
            free(*s);
            *s = NULL;
            return 1;
        }
        (*s)[i] = c;
        (*s)[i + 1] = 0;
    }
    fflush(stdin);
    if (*s == NULL) {
        if ( NULL == ( *s = (char*)realloc(*s,1) ) ) {
            free(*s);
            *s = NULL;
            return 1;
        }
        (*s)[0] = 0;
    }
    return 0;
}

int main() {
    char* str = NULL;
    printf("\nEnter a string\n\n");
    if ( 1 == getline(stdin,&str,false) ) {
        return 1;
    }
    printf("\n%s\n", str);
    if ( str[ strlen(str) ] == 0 ) {
        printf("\nnull-terminated\n");
    }
    free(str);
    str = NULL;
}
```
This getline() function makes the char* dynamic even if it isn't initially, so it still needs to be freed when you are done with it.

For example, if you have:

char* example = "blablablabal"

, you wouldn't have to free(example). However, if you run example through the getline in this last example, you need to free(example) when you are done with it because it makes it dynamic. Also, if you were to run getline() in a loop, the first run of the loop, you might need to set the dynamic argument to false, but the rest of the runs, you'd need to set it to true.

With all that said, if you use std::string and getline(), you don't need to worry about all this.


----------



## Concorde (Jul 28, 2005)

Thanks for your help. I can kind of see what's going on in the codes you provided, but don't quite understand all of it. As I don't know c, and because I would like to use my program as my final(if the final is a program and not a written test or anything like that), I would like to make this entire program of c++, so I probably won't be using those.


----------



## Shadow2531 (Apr 30, 2001)

c methods are allowed in c++, but you can use less c methods by using new and delete instead of realloc if you wanted.

Here's an example. Basically the same as the last example I posted only uses new and delete instead of realloc() and free()


```
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

int getline(FILE* stream, char** s, const bool& dynamic) {
    if (*s != NULL) {
        if (dynamic) {
            delete *s;
        }
        *s = NULL;
    }
    for (size_t i = 0; ; i++) {
        char c = fgetc(stream);
        if (c == '\n') {
            break;
        }
        char* save = new char[i + 1];
        if (save == NULL) {
            if (s != NULL) {
                delete *s;
                *s = NULL;
            }
            return 1;
        }
        if (*s == NULL) {
            *s = new char[1];
           (*s)[0] = 0;
        }
        strcpy(save,*s);
        delete *s;
        *s = NULL;
        *s = new char[i + 2];
        if (*s == NULL) {
            delete save;
            return 1;
        }
        strcpy(*s,save);
        delete save;
        (*s)[i] = c;
        (*s)[i + 1] = 0;
    }
    fflush(stdin);
    if (*s == NULL) {
        *s = new char[1];
        (*s)[0] = 0;
    }
    return 0;
}

int main() {
    char* str;
    printf("\nEnter a string\n\n");
    if ( 1 == getline(stdin,&str,false) ) {
        return 1;
    }
    printf("\n%s\n", str);
    if ( str[ strlen(str) ] == 0 ) {
        printf("\nnull-terminated\n");
    }
    delete str;
    str = NULL;
}
```
On top of that, you could use cout instead of printf, use exceptions (try, catch, throw) instead of the "if function returns 1" error handling. Instead of strcpy, you could use a loop etc. etc.

However, if you are required to use modern c++ methods, you wouldn't be dealing with char arrays for input.

I just provided these things as examples. I'm sure everyone would be willing to address code that you write and probably explain mine too.


----------

