Is there any way to allocate exactly enough space during runtime WITHOUT asking the length of the string?
int main()
{
char **tests;
int counter;
int i;
int j;
int testCases;
scanf(" %d", &testCases);
tests = malloc(sizeof(char *) * testCases);
for(i = 0; i < testCases; i++)
//stuck here, normally I would put tests[i] = malloc(length_of_string)
//but I don't know the length of string until runtime
}
Since you are using scanf
to read the count, I suppose that you will be using it to read the strings as well. If your C library is Posix 2008 compatible [Note 1], then you can use the m
length modifier to a scanf %s
%c
or %[
format, which will cause scanf
to automatically allocate the string for you. (You need to supply the address of a string pointer -- i.e. char**
-- instead of just a string pointer.)
Note that in the scanf format " %d"
, the space character is redundant. The %d
format specifier, like %s
, automatically skips leading whitespace.
Here's an example if you are reading white-space separated words:
int n_strings;
if (scanf("%d", &n_strings) != 1) {
/* Handle input error; do not continue */
}
/* Should check to make sure n_strings is > 0 */
char** strings = malloc(n_strings * sizeof *strings);
if (!strings) {
/* Handle alloc error; do not continue */
}
for (int i = 0; i < n_strings; ++i) {
if (scanf("%ms", &strings[i]) != 1) {
/* Handle input error, do not continue */
}
}
It's more likely that you will be wanting to read in complete lines. In that case, again using a Posix 2008 compatible library, you can use the getline
function, which reads an entire line -- including the newline character -- and stores it into malloc'd storage. Unlike the scanf
m
modifier, getline
requires that the buffer pointer whose address you give it is either NULL or the result of a previous call to malloc
. Also, a successful call will return the number of characters actually stored, which can be handy.
Here's the above example using getline
:
int n_strings;
if (scanf("%d", &n_strings) != 1) {
/* Handle input error; do not continue */
}
/* Skip the rest of the first line */
while (getchar() != '\n') {}
char** strings = malloc(n_strings * sizeof *strings);
if (!strings) {
/* Handle alloc error; do not continue */
}
for (char **strp = strings, **limit = strings + n_strings;
strp < limit;
++strp) {
size_t n = 0;
*strp = NULL;
ssize_t len = getline(strp, &n, stdin);
if (len <= 0) {
/* Handle input error, do not continue */
}
/* You probably don't want the trailing newline. But remember
* that is is possible that it doesn't exist if the last character
* in the file is not a newline.
*/
if (len && (*strp)[len - 1] == '\n')
(*strp)[len - 1] = 0;
}
As far as I know, the standard C library will conform to Posix 2008 if you are using reasonably modern Linux or Mac OS X. Both the features recommended here were implemented in the Gnu standard C library before being incorporated into the standard.
To enable Posix 2008 features, you will need to put one (or both) of these lines in your source code before any system include:
#define _POSIX_C_SOURCE 200809L
#define _XOPEN_SOURCE 700
If you are using an older glibc
, in which getline
and the m
flag were still considered Gnu extensions, use this definition:
#define _GNU_SOURCE