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++).
Code:
#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*.
Code:
#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.
Code:
#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.