Here are some of the issues in your code:
Return pointer malloc() is not being checked. It needs to be checked as the void* pointer from it can return NULL if unsuccessful. You can check malloc() like this:
ptr = malloc(......);
if (ptr == NULL) {
/* handle error */
}
Return value of scanf() is not being checked. This needs to check if 1 integer value for numstr was found. You can verify this like:
if (scanf("%d", &numstr) != 1) {
/* handle error */
}
strings[i] is not being allocated properly. Since this is a char* pointer, you need to allocate a number of char bytes, not char* pointers. You also need to add +1 to your allocation, to ensure their is enough space for the null-terminator \0. So instead of:
strings[i] = malloc(strlen(input) * sizeof(char*));
You can do:
strings[i] = malloc(strlen(input)+1);
Note: sizeof(char) is always 1, so no need to include it here.
Your code does not update **strings on the second numstr. This will lead to issues if numstr ends up being a bigger, in which you will be accessing beyond the limit of **strings. You may need to use realloc(3) here, to resize your block of memory. A way you can do this is to keep track of the first numstr, then check it against the second numstr, and if they are different, resize strings.
Here is an example:
prev_numstr = numstr;
printf("Enter number of strings for set 2:\n");
if (scanf("%zu ", &numstr) != 1) {
/* handle exit */
}
if (numstr != prev_numstr) {
void *temp = realloc(strings, numstr * sizeof(*strings));
if (temp == NULL) {
/* handle exit */
}
strings = temp;
}
Since scanf() leaves a \n character in the input buffer, you need to get rid of this before your call to fgets(). You can simply add a space by doing scanf("%d ", &num_of_str), which will consume any white space still left in the buffer.
fgets() must be checked, as it can return a NULL pointer on failure to read a line. It also appends a \n character at the end of the buffer, so you might need to remove this newline sometime.
Any heap allocation made with malloc() and realloc() must be de-allocated with free(3) at the end.
Since void *malloc(size_t size) expects size_t, it is better to use size_t variables here instead.
Since your code doesn't have issues with sorting, here is some example code that uses these points:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINESIZE 100
int main(void) {
char input[LINESIZE];
size_t numstr, prev_numstr, slen;
void *temp = NULL;
printf("Enter number of strings for set 1:\n");
if (scanf("%zu ", &numstr) != 1 || numstr < 1) {
fprintf(stderr, "Invalid value\n");
exit(EXIT_FAILURE);
}
char **strings = malloc(numstr * sizeof(*strings));
if (strings == NULL) {
fprintf(stderr, "Cannot allocate %zu strings\n", numstr);
exit(EXIT_FAILURE);
}
/* Set 1 */
for (size_t i = 0; i < numstr; i++) {
if (fgets(input, LINESIZE, stdin) != NULL) {
slen = strlen(input);
/* removes newline */
if (slen > 0 && input[slen-1] == '\n') {
input[slen-1] = '\0';
}
strings[i] = malloc(strlen(input)+1);
if (strings[i] == NULL) {
fprintf(stderr, "Cannot allocate %zu bytes for string\n", strlen(input)+1);
exit(EXIT_FAILURE);
}
strcpy(strings[i], input);
}
}
/* keeps track of previous number of strings */
prev_numstr = numstr;
printf("Enter number of strings for set 2:\n");
if (scanf("%zu ", &numstr) != 1 || numstr < 1) {
fprintf(stderr, "Invalid value\n");
exit(EXIT_FAILURE);
}
/* only enters if size is different */
if (numstr != prev_numstr) {
temp = realloc(strings, numstr * sizeof(*strings));
if (temp == NULL) {
fprintf(stderr, "Cannot reallocate %zu spaces\n", numstr);
exit(EXIT_FAILURE);
}
/* perhaps temp could could freed here */
strings = temp;
}
/* Set 2 */
for (size_t i = 0; i < numstr; i++) {
if (fgets(input, LINESIZE, stdin) != NULL) {
slen = strlen(input);
if (slen > 0 && input[slen-1] == '\n') {
input[slen-1] = '\0';
}
strings[i] = malloc(strlen(input)+1);
if (strings[i] == NULL) {
fprintf(stderr, "Cannot allocate %zu bytes for string\n", strlen(input)+1);
exit(EXIT_FAILURE);
}
strcpy(strings[i], input);
}
}
/* printing and freeing strings */
for (size_t i = 0; i < numstr; i++) {
printf("%s\n", strings[i]);
free(strings[i]);
strings[i] = NULL;
}
/* freeing double pointer 'strings' itself */
free(strings);
strings = NULL;
exit(EXIT_SUCCESS);
}
Note: I assumed you still wanted to take in 2 sets, and overwrite the first one with the second one, which does seem odd, however.
strings[i] = malloc(strlen(input) * sizeof(char*));is missing 1 for null-termination char, and thesizeof(char*)error makes up for it but allocating 4 or 8 times the required size...strings[i] = malloc(strlen(input)+1);would be correct.malloc(strlen(input) * sizeof(char*));-->malloc(strlen(input) + 1);to allocate room for\0and the sizeof is unnecessary and should not be sizeof pointer.