I am new to C have come across a problem that I think some of you may have had in the past. I am trying to code a program that has the user input a bunch of grades and the program tells you how many A,B,C,D,Fs you have entered.
How ever, the problem is that my counter for the grades just wont work.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include<stdint.h>
//MACRO
#define F_Range (0-49)
#define D_Range (50-59)
#define C_Range (60-69)
#define B_Range (70-79)
#define A_Range (80-100)
#define A_COUNTer
#define B_COUNTer
#define C_COUNter
#define D_COUNTer
#define F_COUNTer
//Function Prototype
void display(void);
int main(int argc, char** argv) {
{
float input, F_Counter, D_Counter, C_Counter, B_Counter, A_Counter;
printf("Total Number of grades 'A' (80-100) = %.2f",A_Counter);
//the rest of the displays would go here
do
{
fflush (stdin);
scanf("%f",&input); //Get input from user
if (input == F_Range);
{
F_Counter++;
}
if (input == D_Range);
{
D_Counter++;
}
if (input == C_Range);
{
C_Counter++;
}
if (input == B_Range);
{
B_Counter++;
}
if (input == A_Range);
{
A_Counter++;
}
}
while (input != 999);
//Exit
{
}
return 0;
}
}
ok so for start when using #define x y you simply say "change all the reference to 'x' with 'y'" so when you have
#define C_Range (60-69)
and then
if (input == C_Range );
it iterputes as
if (input == (60-69));
which makes no sense, plus you have the ";" at the end of the if statement which doesn't make sense either
instead use:
#define F_RangeLow 0
#define F_RangeHigh 49
and the if statement
if (input >= F_RangeLow && input <= F_RangeHigh )
now another thing you have to do is to initiate the counter with 0. that's because you want to stat counting from 0...
float F_Counter=0;
there is no need for 2 "{" at the start of the main
this is quite enough:
int main(int argc, char** argv) {
.
.
.
}
Your counter variables are uninitialized. So, they hold unknown values. So you have to change float input, F_Counter, D_Counter, C_Counter, B_Counter, A_Counter; to float input, F_Counter=0, D_Counter=0, C_Counter=0, B_Counter=0, A_Counter=0;
Your code has multiple major issues.
The first is that your Range macros don't expand to working code:
#define F_Range (0-49)
…
if (input == F_Range);
This expands to:
if (input == (0-49));
which is only true if input is -49. If you want to check if input is between 0 and 49, you'll have to do that explicitly:
if (input >= 0 && input <= 49)
Given your current level of understanding of C, it's probably best if you don't use macros for now. Leave them alone, write out code in full, and start using macros once you have a firm grasp of the language.
The following line:
printf("Total Number of grades 'A' (80-100) = %.2f",""A_Counter);
^^
has a stray pair of quotation marks. (Does this even compile?)
Additionally:
You've got a semicolon at the end of the if statement mentioned above, which makes it not work correctly.
Your counter variables are not initialized to zero.
float input, F_Counter, D_Counter, C_Counter, B_Counter, A_Counter;
In the main() context you are incrementing these values and none of them are initialized. You have undefined behavior when you have uninitialized vairables.
The values should be initialized like
float input =0,F_Counter=0;/* similarly for the rest */
Checking the range using the macros also needs to be fixed (0-49) doesn't mean you are checking the range from 0 to 49 . Comparison operators should be used in these cases.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <stdint.h>
#define S_(x) #x
#define S(x) S_(x)
#define RANGE_S(x) S((x##_Range))
#define COUNTER(x) x##_Counter
#define DISP(x) \
printf("Total Number of grades '%c' %s = %d\n",\
CHAR(x), RANGE_S(x), COUNTER(x))
#define CHECK(var, x) atoi(S(x##_Range)) <= var
#define CHAR(x) *#x
#define F_Range 0-49
#define D_Range 50-59
#define C_Range 60-69
#define B_Range 70-79
#define A_Range 80-100
void display(void);
int main(int argc, char** argv) {
float input;
int COUNTER(A)=0, COUNTER(B)=0, COUNTER(C)=0, COUNTER(D)=0, COUNTER(F)=0;
while(scanf("%f", &input)==1 && input != 999.f){
if (CHECK(input, A)){
++COUNTER(A);
} else if(CHECK(input, B)){
++COUNTER(B);
} else if(CHECK(input, C)){
++COUNTER(C);
} else if(CHECK(input, D)){
++COUNTER(D);
} else if(CHECK(input, F)){
++COUNTER(F);
}
}
DISP(A);
DISP(B);
DISP(C);
DISP(D);
DISP(F);
return 0;
}
Try Something Like This
#define F_Range(x) (x>=0 && x<=49)?true:false
#define D_Range(x) (x>=50 && x<=59)?true:false
#define C_Range(x) (x>=60 && x<=69)?true:false
#define B_Range(x) (x>=70 && x<=79)?true:false
#define A_Range(x) (x>=80 && x<=89)?true:false
AND
scanf("%f",&input); //Get input from user
if (F_Range(input));
{
F_Counter++;
}
else if (D_Range(input))
{
D_Counter++;
}
else if (C_Range(input))
{
C_Counter++;
}
else if (B_Range(input))
{
B_Counter++;
}
else if (A_Range(input))
{
A_Counter++;
}
Related
I've been trying to make a username and password interface and I was wondering if it was possible to have an or statement within strcmp and if I could also use all values of the array within 1 string, Thanks!
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int u, p;
char Iuser[50],Ipass[50];
char user[3][50] = { "user1", "user2", "user3" };
char pass[3][50] = { "pass1", "pass2", "pass3" };
printf("\n Enter your username:");
gets(Iuser);
u = strcmp(user[0|1|2], Iuser);
if (u == 0) {
printf("\n Enter your password");
scanf("%s", &Ipass);
} else {
printf("\n Invalid Username, Try Again !");
}
}
No, you can't do like that in C.
I'm stealing Aconcagua's comment about what it actually does:
user[0|1|2] first calculates 0|1|2, then accesses the array. Result of bitwise OR-ing 0, 1 and 2 is 3, though, which already is out of bounds of your user array, thus undefined behaviour
So, instead of
u=strcmp(user[0|1|2],Iuser);
if(u==0) {
You should do:
#include <stdbool.h>
bool u = strcmp(user[0], Iuser) == 0 ||
strcmp(user[1], Iuser) == 0 ||
strcmp(user[2], Iuser) == 0;
if(u) {
If the array of users is long or the number of users is not known at compile-time:
bool u = false;
for(int i = 0; i < number_of_users; ++i) {
if(strcmp(user[i], Iuser) == 0) {
u = true;
break;
}
}
if(u) {
Note: Don't use bitwise OR, |, for these comparisons. Using the logical OR, ||, enables short-circuit evaluation so that it stops testing as soon as one condition is true, just like the loop above which breaks out as soon as one condition has been found true.
strcmp cannot be used this way: user[0|1|2] evaluates to user[3], which accesses an element of the array beyond the end of the array: strcmp() will have undefined behavior when it reads from this place.
The C library does not have a generic function to locate a string in an array, so you should write:
u = strcmp(user[0], Iuser) && strcmp(user[1], Iuser) && strcmp(user[2], Iuser);
Which is quite verbose and specific.
Note that you should always ask for a password to avoid giving information about user names to an intruder, so the code should be modified as:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char Iuser[50];
char Ipass[50];
char user[3][50] = { "user1", "user2", "user3" };
char pass[3][50] = { "pass1", "pass2", "pass3" };
int nusers = sizeof(user) / sizeof(user[0]); // number of users
int u;
for (;;) {
printf("\n Enter your username:");
if (scanf("%49s", Iuser) != 1)
return 1;
printf("\n Enter your password");
if (scanf("%49s", Ipass) != 1)
return 1;
for (u = 0; u < nusers; u++) {
if (strcmp(user[u], Iuser) == 0 && strcmp(pass[u], Ipass) == 0)
break;
}
if (u < nusers)
break;
printf("\n Invalid Username and/or password, Try Again !");
}
// user has been authenticated.
// ...
return 0;
}
Note also that password should be read without echoing the characters to the terminal, which is tricky but can be achieved on unix systems via getpass:
#include <pwd.h>
#include <unistd.h>
char *getpass(const char *prompt);
Passwords should not be stored in clear text as you do, nor as encrypted text because they would be too easy to find. Computing a cryptographic hash is recommended, in addition to more advanced techniques.
You should do
u=strcmp(user[0],Iuser)!=0 && strcmp(user[1], Iuser)!=0 && strcmp(user[2],Iuser)!=0;
if(u==0) {
//User exists so ask password
because strcmp accepts only two strings to compare. If you do a OR as u said it would be something strange like bitwise operation inside char arrays, I doubt it would ever compile and we don't want to do that.
Have a good day.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define LEN_ID 3
#define LEN_P 30
#define LEN_CIDADE 50
#define AT 40
typedef struct aeroporto
{
char id[LEN_ID + 1];
char pais[LEN_P + 1];
char cidade[LEN_CIDADE + 1];
} Aeroporto;
int findavailablespot(Aeroporto l[AT])
{
int i = found = 0;
for (;i<AT;i++) {
if (l[i] = {"aaa","bbb","ccc"}) //Error in this line
break;
if (found)
return i;
else
return -1;
}
}
So i am creating the structure aeroporto then a vector made up of aeroportos and i want to check if {"aaa","bbb","ccc"} shows up inside the vector.
Help?
Sorry for the formatting, new at this
You have to use strcmp() to compare strings. There's no shortcut for doing this with all the members of a structure, you have to test each one individually and combine with &&.
You also forgot to set found before breaking out of the loop.
int i = 0, found = 0;
for (;i<AT;i++) {
if (strcmp(l[i].id, "aaa") == 0 && strcmp(l[i].pais, "bbb") == 0 && strcmp(l[i].cidade, "ccc")) {
found = 1;
break;
}
}
I'm having a really hard time adjusting function to my needs. First of all look at those three files and notice how I have to call f_texture function in main function in order to make it work:
externs.h
#ifndef EXTERNS_H_
#define EXTERNS_H_
extern char t_about[100];
extern int friction;
extern int f_texture(char* ,char*);
#endif
functionA.c
#include <stdio.h>
#include "externs.h"
int main()
{
f_texture("rough","friction");
printf("Friction: %d\n", friction);
f_texture("rough","t_about");
return 0;
}
functionB.c
#include "externs.h"
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
char t_about[100];
int friction;
int f_texture(char* texture,char* what_is_needed)
{
/*Checking if both values are present*/
assert(what_is_needed);
assert(texture);
/*Static array in order to prevent it's disappearance*/
memset(t_about, '\0', sizeof(t_about));
/*Configuring variables for desired texture*/
if (strcmp(texture, "smooth") == 0)
{
strcpy(t_about, "The surface is perfectly smooth, without any "
"protuberances.\n");
friction = 0;
}
else if (strcmp(texture, "rough") == 0)
{
strcpy(t_about, "Rough bumps can be feeled under my fingertips.\n");
friction = 4;
}
/*In case of absent keyword of desired texture it will crash the program*/
else
{
assert(!what_is_needed);
}
/*Returning desired value*/
if (strcmp(what_is_needed, "t_about") == 0)
{
int i=0;
while (t_about[i] != '\0')
{
printf("%c", t_about[i]);
i++;
}
}
else if (strcmp(what_is_needed, "friction") == 0)
{
return friction;
}
/*In case of absent keyword of desired value it will crash the program*/
else
{
assert(!what_is_needed);
}
return 0;
}
And now here is my question: How to rewrite this code to make it possible to call f_texture function without using quotation marks inside? I mean instead of f_texture("abcd","efgh") just to type f_texture(abcd,efgh). I've noticed that this way it's required just after I've wrote this code.
Thanks in advance.
If you don't want to assign string constants to variables or preprocessor object macros, another option is to use preprocessor function macros, using the stringification feature:
#define call_f_texture(a,b) f_texture(#a,#b)
....
call_f_texture(rough,friction);
The C preprocessor will turn this into
f_texture("rough","friction");
You can also use some macros:
#define ROUGH "rough"
#define FRICTION "friction"
#define T_ABOUT "t_about"
int main()
{
f_texture(ROUGH, FRICTION);
printf("Friction: %d\n", friction);
f_texture(ROUGH, T_ABOUT);
return 0;
}
You can do like this,
char rough[]="rough";
char friction[]= "friction";
and call
f_texture(rough, friction);
char a[MAX] = "rouch";
char b[MAX} = "friction";
int main()
{
f_texture();
...
}
int f_texture()
{
/*Checking if both values are present*/
assert(b);
assert(a);
}
or
int f_texture(char* a,char* b)
{
/*Checking if both values are present*/
assert(b);
assert(a);
...
}
int main()
{
char a[MAX] = "rouch";
char b[MAX} = "friction";
f_texture(a,b);
...
}
I have a C program with some definitions for error codes. Like this:
#define FILE_NOT_FOUND -2
#define FILE_INVALID -3
#define INTERNAL_ERROR -4
#define ...
#define ...
Is it possible to print the name of the definition by its value? Like this:
PRINT_NAME(-2);
// output
FILE_NOT_FOUND
In short, no. The easiest way to do this would be something like so (PLEASE NOTE: this assumes that you can never have an error assigned to zero/null):
//Should really be wrapping numerical definitions in parentheses.
#define FILE_NOT_FOUND (-2)
#define FILE_INVALID (-3)
#define INTERNAL_ERROR (-4)
typdef struct {
int errorCode;
const char* errorString;
} errorType;
const errorType[] = {
{FILE_NOT_FOUND, "FILE_NOT_FOUND" },
{FILE_INVALID, "FILE_INVALID" },
{INTERNAL_ERROR, "INTERNAL_ERROR" },
{NULL, "NULL" },
};
// Now we just need a function to perform a simple search
int errorIndex(int errorValue) {
int i;
bool found = false;
for(i=0; errorType[i] != NULL; i++) {
if(errorType[i].errorCode == errorValue) {
//Found the correct error index value
found = true;
break;
}
}
if(found) {
printf("Error number: %d (%s) found at index %d",errorType[i].errorCode, errorType[i].errorString, i);
} else {
printf("Invalid error code provided!");
}
if(found) {
return i;
} else {
return -1;
}
}
Enjoy!
Additionally, if you wanted to save on typing even more, you could use a preprocessor macro to make it even neater:
#define NEW_ERROR_TYPE(ERR) {ERR, #ERR}
const errorType[] = {
NEW_ERROR_TYPE(FILE_NOT_FOUND),
NEW_ERROR_TYPE(FILE_INVALID),
NEW_ERROR_TYPE(INTERNAL_ERROR),
NEW_ERROR_TYPE(NULL)
};
Now you only have to type the macro name once, reducing the chance of typos.
You can do something like this.
#include <stdio.h>
#define FILE_NOT_FOUND -2
#define FILE_INVALID -3
#define INTERNAL_ERROR -4
const char* name(int value) {
#define NAME(ERR) case ERR: return #ERR;
switch (value) {
NAME(FILE_NOT_FOUND)
NAME(FILE_INVALID)
NAME(INTERNAL_ERROR)
}
return "unknown";
#undef NAME
}
int main() {
printf("==== %d %s %s\n", FILE_NOT_FOUND, name(FILE_NOT_FOUND), name(-2));
}
No, that's not possible. What would this print?
#define FILE_NOT_FOUND 1
#define UNIT_COST 1
#define EGGS_PER_RATCHET 1
PRINT_NAME(1);
Kinda ...
#define ERROR_CODE_1 "FILE_NOT_FOUND"
#define ERROR_CODE_2 "FILE_FOUND"
#define PRINT_NAME(N) ERROR_CODE_ ## N
or:
static char* error_codes(int err) {
static char name[256][256] = {
};
int base = .... lowest error code;
return name[err - base];
}
#define PRINT_NAME(N) error_code(N)
Why not elect to use an enumeration instead?
enum errors {FILE_NOT_FOUND = -2, FILE_INVALID = -3, INTERNAL_ERROR = -4};
FILE *fp = fopen("file.txt", "r");
if(fp == NULL) {
printf("Error\n");
exit(FILE_NOT_FOUND);
}
Not automatically. The name is losing during compilation, and only the constant number remains in the code.
But you can build something like this:
const char * a[] = {"","","FILE_NOT_FOUND","FILE_INVALID"};
and access it by using the define value absolute value as index.
Use designated initializers of C99 for this, but a bit of care is necessary if your error codes are negative.
First a version for positive values:
#define CODE(C) [C] = #C
static
char const*const codeArray[] = {
CODE(EONE),
CODE(ETWO),
CODE(ETHREE),
};
enum { maxCode = (sizeof codeArray/ sizeof codeArray[0]) };
This allocates an array with the length that you need and with the string pointers at the right positions. Note that duplicate values are allowed by the standard, the last one would be the one that is actually stored in the array.
To print an error code, you'd have to check if the index is smaller than maxCode.
If your error codes are always negative you'd just have to negate the code before printing. But it is probably a good idea to do it the other way round: have the codes to be positive and check a return value for its sign. If it is negative the error code would be the negation of the value.
This is how I do it in C:
< MyDefines.h >
#pragma once
#ifdef DECLARE_DEFINE_NAMES
// Switch-case macro for getting defines names
#define BEGIN_DEFINE_LIST const char* GetDefineName (int key) { switch (key) {
#define MY_DEFINE(name, value) case value: return #name;
#define END_DEFINE_LIST } return "Unknown"; }
#else
// Macros for declaring defines
#define BEGIN_COMMAND_LIST /* nothing */
#define MY_DEFINE(name, value) static const int name = value;
#define END_COMMAND_LIST /* nothing */
#endif
// Declare your defines
BEGIN_DEFINE_LIST
MY_DEFINE(SUCCEEDED, 0)
MY_DEFINE(FAILED, -1)
MY_DEFINE(FILE_NOT_FOUND, -2)
MY_DEFINE(INVALID_FILE, -3)
MY_DEFINE(INTERNAL_ERROR -4)
etc...
END_DEFINE_LIST
< MyDefineInfo.h >
#pragma once
const char* GetDefineName(int key);
< MyDefineInfo.c >
#define DECLARE_DEFINE_NAMES
#include "MyDefines.h"
Now, you can use the declared switch-case macro wherever like this:
< WhereEver.c >
#include "MyDefines.h"
#include "MyDefineInfo.h"
void PrintThings()
{
Print(GetDefineName(SUCCEEDED));
Print(GetDefineName(INTERNAL_ERROR));
Print(GetDefineName(-1);
// etc.
}
Does someone know of any C99 preprocessor magic that allows for creating a string consisting of another string repeated N times?
E.g.
STRREP( "%s ", 3 )
becomes
"%s %s %s "
after preprocessing.
The only thing I could think of myself was something like this
#define STRREP( str, N ) STRREP_##N( str )
#define STRREP_0(str) ""
#define STRREP_1(str) str
#define STRREP_2(str) str str
#define STRREP_3(str) str str str
...
which works well, but is ugly as I have to define a macro for each repetition length manually. I want to use it together with variadic macros and the macro returning the number of macro arguments shown here.
Since it's a macro and N is a numeric constant anyway, how about this?
#include <stdio.h>
#define REP0(X)
#define REP1(X) X
#define REP2(X) REP1(X) X
#define REP3(X) REP2(X) X
#define REP4(X) REP3(X) X
#define REP5(X) REP4(X) X
#define REP6(X) REP5(X) X
#define REP7(X) REP6(X) X
#define REP8(X) REP7(X) X
#define REP9(X) REP8(X) X
#define REP10(X) REP9(X) X
#define REP(HUNDREDS,TENS,ONES,X) \
REP##HUNDREDS(REP10(REP10(X))) \
REP##TENS(REP10(X)) \
REP##ONES(X)
int main(void)
{
printf(REP(9,0,7, "*")); // "*" repeated 907 times
printf(REP(0,9,2, "#")); // "#" repeated 92 times
printf(REP(0,0,1, "#")); // "#" repeated 1 times
return 0;
}
My suggestion is to use the boost.
E.g.
#include <stdio.h>
#include <boost/preprocessor/repetition/repeat.hpp>
#define Fold(z, n, text) text
#define STRREP(str, n) BOOST_PP_REPEAT(n, Fold, str)
int main(){
printf("%s\n", STRREP("%s ", 3));//STRREP("%s ", 3) -> "%s %s %s "
return 0;
}
I recently discovered a recursion scheme with the CPP c-preprocessor file inclusion mechanism over the __INCLUDE_LEVEL__ preprocessor literal which is treated automatically - so maybe this algorithm only works for gcc ?!?
The algorithm is conceptually unlimited, it can be extended with additional file indirection.
The herin presented code handles an ITERATION_COUNT from 0-39202
With the comment/uncomment of the ITERATION_SEPARATOR you can
generate N elements, or 1 element with N concatenations, suitable for string repetitions.
The ITERATION_ELEMENT macro is used as the "repetition element"
You can compile the code regulary, without any additional defines. The macro invocation inside the code is idempotent.
An exemplary output:
> gcc iterate.c -o iterate -Wall -s -O3 && ./iterate.exe
0-1591 Counter
1592 Elements
iterate.c:
#include <stdio.h>
#include <inttypes.h>
int main(void) {
const char * preproc_array[] = {
#define ITERATION_COUNT 1592 //0-(199*197-1)39202 (maximum counter)
#define ITERATION_SEPARATOR , //this macro, if active, determines wheather there exits N separate elements otherwise, if outcommented, just 1 element with N concatenations
#define ITERATION_ELEMENT 0-__COUNTER__ Counter\n //the expanded macro as an arbitrary element
#include "iterate.h"
};
return !printf("%s%"PRIu32" Elements",preproc_array[
#ifndef NO_ITERATION_SEPARATOR
__COUNTER__-1
#else
0
#endif
], sizeof(preproc_array)/sizeof(const char *));
}
iterate.h:
#define ITERATION_START 1 //start index of first inclusion
#define ITERATION_LIMIT 199 //conforming to CPP preprocessor manual pg. 54 chapter 11.5, a limit of 200 is set arbitrary
#define ITERATION(...) _ITERATION(__VA_ARGS__)
#define _ITERATION(...) #__VA_ARGS__ ITERATION_SEPARATOR
#ifndef ITERATION_SEPARATOR
#define ITERATION_SEPARATOR
#define NO_ITERATION_SEPARATOR
#endif
//here begins the recursive algorithm via preprocessor file inclusion, enable the warnings if you want to see how it loops through
#if __INCLUDE_LEVEL__ <= ITERATION_COUNT/ITERATION_LIMIT
//~ #warning DIV
#define ITERATION_END ITERATION_COUNT/ITERATION_LIMIT+3 // + offset
#include "loop.h"
#define ITERATION_END ITERATION_LIMIT
#include "loop.h"
#include "iterate.h"
#endif
#if __INCLUDE_LEVEL__ == ITERATION_START
//~ #warning MOD
#define ITERATION_END ITERATION_COUNT%ITERATION_LIMIT+ITERATION_START
#include "loop.h"
#if ITERATION_COUNT % ITERATION_LIMIT
#define ITERATION_END 3 // + offset
#include "loop.h"
#endif
#endif
//end of alogrithm
loop.h:
#if __INCLUDE_LEVEL__ < ITERATION_END
#include "loop.h"
ITERATION(ITERATION_ELEMENT)
#undef ITERATION_END
#endif
Not sure whether it can be done with the macro but you can do it with the function like:
char *strrep(const char *str, int nrep)
{
if (nrep <= 0 || !str) return NULL;
char *buf = malloc(strlen(str) * nrep + 1);
if (!buf) return NULL;
for (int i = 0; i < nrep; ++i) {
strcat(buf, str);
}
return buf;
}
Now you can use it:
char *r = strrep("%s", 3);
if (r) {
...
free(r);
}
UPD: If you want to avoid malloc/free this is a variant of the first code:
/* .h */
#define STRREP_MAX_CHARS 1024
#define STRREP_INIT static char __strrep_buffer[STRREP_MAX_CHARS]
#define STRREP(str, nrep) strrep(str, nrep) ? __strrep_buffer : ""
char *strrep(const char *str, int nrep);
/* .c */
STRREP_INIT;
char *strrep(const char *str, int nrep)
{
if (nrep <= 0 || !str) return 0;
if (strlen(str) * nrep >= STRREP_MAX_CHARS) return 0;
memset(__strrep_buffer, 0, STRREP_MAX_CHARS);
for (int i = 0; i < nrep; ++i) {
strcat(__strrep_buffer, str);
}
return __strrep_buffer;
}
Now:
printf("%s\n", STRREP("%s", 3));
OTOH, this looks even uglier than the first one.
How about something like this?
#define DUP2(str) str str
#define DUP4(str) DUP2(str) DUP2(str)
#define DUP8(str) DUP4(str) DUP4(str)
#define DUP16(str) DUP8(str) DUP8(str)
#define DUP32(str) DUP16(str) DUP16(str)
#define DUP64(str) DUP32(str) DUP32(str)
#define DUP128(str) DUP64(str) DUP64(str)
#define DUP256(str) DUP128(str) DUP128(str)
#define DUP512(str) DUP256(str) DUP256(str)
#define DUP1024(str) DUP512(str) DUP512(str)