Reputation: 871
I am wondering can pure C do following pseudo code?
for(int i = 0; i < N; i++)
func( Multi("str",i));
I know the feature char *tmp = "str1" "str1"
and tried to combine that and macro. But, the only way I come up with is define several macro with different repeat times. My method is bad for concise, are there better method ?
edit:
expect Multi
can return "str" * i times
e.g. char *tmp = Multi("str",3); // now tmp is "strstrstr"
Upvotes: 1
Views: 537
Reputation: 2829
Yes pure C can do a lot my friend, here I have written a function for you
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * strRepeat(char *str, int n) {
int len = strlen(str);
char *repeatedStr = (char *)malloc(len * n + 1);
if(repeatedStr == NULL) {
return NULL;
}
for(int i = 0;i < len * n; i++) {
repeatedStr[i] = str[i % len];
}
repeatedStr[len * n] = '\0';
return repeatedStr;
}
int main(void) {
char *s = strRepeat("str", 7);
printf("%s", s);
//output: strstrstrstrstrstrstr
free(s);
return 0;
}
Upvotes: 0
Reputation: 3498
One way to implement this is to use strncpy
and calloc
to copy the original string several times into a new char array
char* repeat(char* orig, size_t times) {
if (times == 0) return calloc(1, sizeof(char)); // is the empty string
else {
size_t orig_length = strlen(orig);
size_t new_length = times * orig_length;
char* new_str = malloc((new_length + 1) * sizeof(char));
for (size_t i = 0; i < times; i++) {
strncpy(&new_str[orig_length * i], orig, orig_length);
}
new_str[new_length] = 0; // setting the null-byte
return new_str;
}
}
This function return always a new string, which needs to be freed with free
before the last reference to it is lost or else you will have a memory leak.
This could also be done recursive, but this won't do much for this kind of function. And this can most likly be optimized, feel free to suggest improvements.
Upvotes: 1
Reputation: 241861
Not if you expect to be able to use the run-time value of a variable to control the number of repetitions (unless the range of values of that variable is small and known at compile-time).
Macro expansion and literal string concatenation are done as phases during the compilation, before the executable has been produced. The program doesn't yet exist, and certainly cannot be run. The macro preprocessor only sees a variable as an identifier inside the text of the program.
If you will always use a literal integer, then it is possible to do the expansion with the macro preprocessor, although it does indeed require a lot of macros. There are some macro libraries which can help.
If you know the maximum number of repetitions (and have some runtime mechanism to verify that the limit is not exceeded), you could create a single string literal of the maximum size, perhaps using a macro library as mentioned above. You can then get a string literal containing fewer than this maximum by starting int the middle:
#define Multi(literal, rep) \
(&(REP(MAXREP, literal))[((sizeof literal)-1)*(MAXREP-rep)])
For that to work, MAXREP
must be previously #define
d as a (smallish) integer constant (not a constant expression).
Here's a complete example program, using BOOST_PP_REPEAT
from the Boost preprocessor library to define REP
:
#include <stdio.h>
#include <stdlib.h>
#include <boost/preprocessor/repeat.hpp>
#define MAXREP 80
#define REPEATER(z, n, literal) literal
#define REP(n, literal) BOOST_PP_REPEAT(n, REPEATER, literal)
#define Multi(literal, rep) \
(&(REP(MAXREP, literal))[((sizeof literal)-1)*(MAXREP-rep)])
int main(int argc, char** argv) {
int reps = 0;
if (argc > 1) reps = atoi(argv[1]);
if (reps <= 0) reps = MAXREP;
if (reps > MAXREP) {
fprintf(stderr, "Cannot do %d repetitions; maximum is %d\n", reps, MAXREP);
exit(1);
}
for (int i = 0; i < reps; ++i) printf("%s\n", Multi("foo", i));
return 0;
}
Sample run:
$ make rep
cc -O0 -Wall -ggdb -std=c11 -D_XOPEN_SOURCE=700 -mtune=native rep.c -o rep
$ ./rep 5
foo
foofoo
foofoofoo
foofoofoofoo
Upvotes: 2
Reputation: 154315
Perhaps something employing a compound literal (since C99) to form the space needed?
MULTI(some_string_literal, n)
is valid until the end of the block. No need to free.
#include <string.h>
char *Multi(char *dest, const char *s, unsigned n) {
size_t len = strlen(s);
char *p = dest;
while (n-- > 0) {
memcpy(p, s, len);
p += len;
}
*p = 0;
return dest;
}
// compound literal v-------------------------------v
#define MULTI(s, n) Multi( (char [(sizeof(s) - 1)*n + 1]){0} , (s), (n))
#include <stdio.h>
int main() {
char *tmp = MULTI("str", 3);
printf("<%s>\n", tmp);
printf("<%s> <%s>\n", MULTI("str", 4), MULTI("str", 5));
printf("%p\n", MULTI("str", 6));
}
Sample output
<strstrstr>
<strstrstrstr> <strstrstrstrstr>
0xffffcb80
Upvotes: 1