I'm trying to implement my own printf, I have an issue handling wide char %S.
void my_printf(char *format, ...)
{
char *traverse;
va_list arg;
va_start(arg, format);
traverse = format;
while (*traverse)
{
if (*traverse == '%')
{
*traverse++;
if (*traverse == 'S')
printf("%S\n", va_arg(arg, wchar_t));
*traverse++;
}
else
putchar(*traverse++);
}
va_end(arg);
}
warning: format specifies type 'wchar_t *' (aka 'int *') but the argument has type 'wchar_t' (aka 'int') [-Wformat]
printf("%S\n", va_arg(arg, wchar_t));
when I use following code printf works fine.
printf("%S\n", L"Some String");
You're passing a pointer and retrieving an integer. The types of L"Some String" and va_arg(arg, wchar_t), do not match.
Retrieve a pointer instead:
va_arg(arg, wchar_t*)
The line *traverse++; is not correct, the dereference is redundant. It should be simply: traverse++;
On a side note, your code doesn't do any input checking and a malicious string will cause undefined behavior. This will happen if the character '%' is the last character, the iterator traverse will point to one beyond the last element in the array and the check while (*traverse) will dereference it.
Related
what I have is a string that I get from txt file.
fgets(num_string, lenght, file);
num_string = "011110110101"
So than I select the first number and display it:
printf("Number: %c", num_string[0]);
After that my program gets all the numbers in string with this loop and it should then check each number if its 0 or 1:
for(j=0; j<=11; j++){
printf("numbers: %c\n", num_string[j]);
if(strcmp(num_string[j], zero)==0){
num_of_zeros++;
printf("\nNum of zeros: %d", num_of_zeros);
}
else{
num_of_ones++;
printf("\nNum of ones: %d", num_of_ones);
}
}
But the if statement does not want to work. Here is the problem that it writes in terminal:
AOC_2021_day_3.c: In function 'main':
AOC_2021_day_3.c:27:27: warning: passing argument 1 of 'strcmp' makes pointer from integer without a cast [-Wint-conversion]
if(strcmp(num_string[j], zero)==0){
^~~~~~~~~~
In file included from AOC_2021_day_3.c:3:0:
c:\mingw\include\string.h:77:38: note: expected 'const char *' but argument is of type 'char'
_CRTIMP __cdecl __MINGW_NOTHROW int strcmp (const char *, const char *) __MINGW_ATTRIB_PURE;
^~~~~~
I would appreciate any help :D
strcmp is for comparing to cstrings. In this case, you do not need strcmp at all. You want to check whether a specific character inside num_string is 0 or not. The if(strcmp(num_string[j], zero)==0) statement can be replaced with if(num_string[j] == '0').
I'm studying an exercise of making a simple code that has the function that acts the same way as printf using a variadic function.
Also, I wish to use sprintf and putchar, and not printf.
The code seems to act and give the results as it should do (i.e print a character for %c, and an integer for %d).
However, I keep getting a warning message for putchar(cStr); that says Passing Argument 1 of 'putchar' makes integer from pointer without a cast.
Also, I get a note that says expected int but argument is of type char *.
I've tried to get this solved by changing putchar(cStr); into putchar(*cStr);, but then the code gives me a segment fault.
What should I do to get the warning message and note solved?
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
void new_printf(const char*format, ...);
int main(void)
{
new_printf("A single character : %c An integer : %d \n", 'T', 37);
return 0;
}
void new_printf(const char *format, ...)
{
va_list ap;
char ary[50];
char *cStr;
int iNum, i=0;
va_start(ap, format);
while(*format)
{
if(strncmp(format, "%d",2) == 0){
iNum = va_arg(ap, int);
sprintf(ary, "%d", iNum);
while(ary[i]!='\0'){
putchar(ary[i]);
i++;
}
format = format + 2;
}
else if(strncmp(format, "%c", 2)==0)
{
cStr = va_arg(ap, char*);
putchar(cStr);
format = format + 2;
}
else{
putchar(*format);
format++;
}
}
va_end(ap);
}
The correct results would be as follows:
A single character : T An integer : 37
In the call new_printf("A single character : %c An integer : %d \n", 'T', 37);, 'T' is passed for the %c conversion. 'T' is a character: It is a small integer value. It is not a pointer. For historic reasons, its type is int. This is a correct thing to pass for %c.
Under else if(strncmp(format, "%c", 2)==0), in cStr = va_arg(ap, char*);, you tell va_arg to give you the next argument and that that argument is a char *. It is not. It is an int.
You should retrieve it with va_arg as an int and assign it to an int, not to char *, or simply use it directly as an int.
You should use int x = va_arg(ap, int); putchar(x); or simply putchar(va_arg(ap, int));.
I am trying to recode a printf function so I need to use va_arg since printf is a variadic function.
The thing is, when I want to print out the arguments of my_printf, they can be %i (int) or %s (char *) if we take these two basic possibilities.
So when I go through my va_list ap, I tried to put a variable in the va_arg function so I can change the type to be written, like this:
char *str = NULL;
str = ft_set_my_types(flags[cur_arg]);
ft_putstr(va_arg(ap, str));
with my function ft_set_my_types being something like:
char *ft_set_my_types(char *flags)
{
char **tab = NULL;
tab = ft_alloc_mem2(2, 15); /* this function malloc a tab */
char a = 65;
/* the example here is only with two types of variables */
/* I am sending flags %s in my example which correspond to "char *" */
tab['s'] = "char *";
tab['d'] = "int ";
size_t len = ft_strlen(flags) - 1;
while (a < 123)
{
if (a == flags[len])
break ;
else
a++;
}
return (tab[a]);
}
The "char *flags" being everything between the "%" and the flag (included) of my_printf.
The problem is: when I compile it does not understand my tab['s'] as char * but as "char *" so I get this error:
ft_print.c:63:25: error: unknown type name 'str'
ft_putstr(va_arg(ap, str));
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/7.0.2/include/stdarg.h:35:50: note:
expanded from macro 'va_arg'
#define va_arg(ap, type) __builtin_va_arg(ap, type)
1 error generated.
Could you help me to figure out how I can insert my variable *str in this va_arg function?
C is statically typed. All data types are determined at compile time. You cannot obtain the data type for a declaration by calling a function.
Instead, to handle variadic arguments whose type is not known until run time, you must branch based on the selected data type, via a switch statement or an if/else if/else nest. In each alternative, use the va_arg macro to obtain the argument, with the appropriate static type handled by that alternative. You may be able to perform the type-specific processing in helper functions, if you like.
For example,
/* ... */
switch (field_code) {
case 'i':
do_something_with_int(va_arg(ap, int));
break;
case 's':
do_something_with_string(va_arg(ap, char *));
break;
default:
handle_error();
break;
}
/* ... */
Note that the second argument to va_arg is the type itself, not a string representation of it.
I am trying to print the value of a double and an int. Both are pointers because I use sscanf to get the information for each value. My code compiles, but I have 2 warnings. The warnings are:
a4Functions.c:47:9: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘int *’ [-Wformat=]
a4Functions.c:47:9: warning: format ‘%lf’ expects argument of type ‘double’, but argument 5 has type ‘double *’ [-Wformat=]
and my code is :
void parser(int argc, char ** argv)
{
FILE * songs;
char songString[ROOM_STRING_LENGTH];
char * theString;
char artist[ROOM_STRING_LENGTH];
char title[ROOM_STRING_LENGTH];
int * lengthPointer;
double * sizePointer;
char type[ROOM_STRING_LENGTH];
lengthPointer = 0;
sizePointer = 0;
songs = fopen(argv[1], "r");
if(songs == NULL)/*returns an error if file wasnt opened*/
{
printf("error opening file\n");
}
while(fgets(songString, ROOM_STRING_LENGTH, songs) != NULL)/*gets one string at a time until fgets equals NULL*/
{
theString = malloc((sizeof(char)*(strlen(songString)+1)));
strcpy(theString, songString);
sscanf(theString, "%s,%s,%d,%lf,%s", artist, title, lengthPointer, sizePointer, type);
printf("%s,%s,%d,%lf,%s\n", artist, title, lengthPointer, sizePointer, type);
}
}
You need to dereference the pointer first.
printf("%s,%s,%d,%lf,%s\n", artist, title, *lengthPointer, *sizePointer, type);
What I would do in this case is not using pointer for both variables, but just regular variables, and use & operator in the sscanf call.
Also you need to allocate memory first before using the lengthPointer and sizePointer. And don't forget to free them after you finished.
Need space for the data and need to pass pointers to sscanf()
// int * lengthPointer;
int lengthPointer;
// double * sizePointer;
double sizePointer;
...
//sscanf(theString, "%s,%s,%d,%lf,%s", artist, title, lengthPointer, sizePointer, type);
sscanf(theString, "%s,%s,%d,%lf,%s", artist, title, &lengthPointer, &sizePointer, type);
// No change
printf("%s,%s,%d,%lf,%s\n", artist, title, lengthPointer, sizePointer, type);
BTW: Be sure to free theString when you are done.
free(theString);
}
I have the following code which is failing with EXC_BAD_ACCESS (code=1) and has the following warning:
Incompatible integer to pointer conversion passing 'int' to parameter of type 'const char *'
char *printb(fmt,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
{
static char string[256];
sprintf(string,fmt,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10);
return(string);
}
printb is being called by this code:
if (gotargs) fname = *(argv++);
else do {
printf("file name #%d: ", i+1);
fname = gets(inbuf);
} while (*fname == 0);
if ((gbuf=fopen(fname, "r")) == NULL)
error(printb("I can't find '%s'", fname));
printf("reading '%s'...\n", fname);
if (fgets((lp = inbuf), 512, gbuf) == NULL)
error("file is empty");
Also, how can I convert the gets() to fgets() properly?
Thanks
Well, why did you use the ancient-style function declaration
char *printb(fmt,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
{
?
This declaration declares all arguments as ints. Your attempts to pass a char * pointers to this function will only lead to disaster. Moreover, you are not supplying all parameters in your printb calls, which is another disaster.
It looks like you are attempting to implement a function with variable number of arguments. Specifically for that the language supports ... parameter declaration. Read about variadic functions and va_list.
Your function would be implemented along the lines of
char *printb(const char *fmt, ...)
{
static char string[256];
va_list va;
va_start(va, fmt);
vsprintf(string, fmt, va);
va_end(va);
return string;
}
or better
...
vsnprintf(string, sizeof string, fmt, va);
...
Although the idea of returning a pointer to an internal static buffer is also flawed.
Meanwhile, trying to "emulate" variadic arguments by your method is hopeless. It won't work.