Hey everyone. Been a while since I posted last. I decided to brush up on my C programming skills and try to code a little program for me and my friends to use for a role playing game that we play. Anyways, here's the problem:
Basically what I'm trying to do is write my own version of sprintf that will dynamically allocate memory for the output string based on the length of the input strings. The purpose for this is to make building SQL statements easier; I don't want to have to worry about how long some of the table name, and other values are and allocate unnecessarily large spaces for each statement.
The my_sprintf function works by first reallocating space for the first input string into the variable str. When it encounters a % character it reallocates space for the first and second input strings and replaces the % character with the second input string. When it encounters another % character it reallocates space for the (newly lengthened) str and the third input string and replaces the % character with the third input string. And so on.
The function is only intended to work with strings for simplicity. I'll just use itoa() when any integers get involved. The program below should print out "SELECT 'John Doe' FROM 'Company'".
The problem is that realloc is returning a NULL pointer the next time it is run in the for loop. I can't for the life of my figure out why. Also, this is my first time creating a function with a variable number of inputs. If I've made a mistake in that area, I wouldn't be surprised.
I apologize for that lack of comments in the code. I've been meaning to go back and comment it, but haven't gotten around to it. And personally, I find short bits of code like this easier to read when there isn't a comment every other line.
Code:int my_sprintf(char **str, char *format, ...);
int main() {
char *sql_string=malloc(sizeof(char));
char name[]="John Doe";
char people[]="Company";
my_sprintf(&sql_string,"SELECT '%' FROM '%'",name,people);
printf("%s\n",sql_string);
free(sql_string);
return 0;
}
int my_sprintf(char **str, char *format, ...) {
va_list ap;
char *first_string;
char *next_arg;
//Allocate space for "SELECT '%' FROM '%'" and write it into str
va_start(ap, format);
first_string=malloc((strlen(format)+1)*sizeof(char));
(*str)=realloc((*str),(strlen(format)+1)*sizeof(char));
for (int i=0;i<=strlen(format);i++) {
first_string[i]=format[i];
}
//i is the position in the first string
//j is the position in the entire output string including arguments that are inserted in place of %'s
//k is the position in each of the arguments that will be replacing the %'s
int i=0;
int j=0;
for (;i<=strlen(first_string);i++, j++) {
if (first_string[i]=='%') {
//The first run will allocate space for "SELECT 'John Doe' FROM '%'"
//The second run will allocate space for "SELECT 'John Doe' FROM 'Company'"
next_arg=va_arg(ap, char *);
(*str)=realloc((*str),(strlen((*str))+strlen(next_arg)+1)*sizeof(char)); //The problem is right here. realloc returns NULL the second time the for loop runs.
for (int k=0;k<strlen(next_arg);k++, j++) {
(*str)[j]=next_arg[k];
(*str)[j+1]='\0';
}
j--;
}
else {
//For all other non-% characters, write the next character from the first string into str
(*str)[j]=first_string[i];
}
}
va_end(ap);
free(first_string);
return 0;
}