Issue
can anyone help with this project task?
I am to build a custom printf funcion after my C classes.
I'm restricted to use most standard C functions.
Must follow Aunty Betty coding style and below is the authorised functions and macros
write (man 2 write) malloc (man 3 malloc) free (man 3 free) va_start (man 3 va_start) va_end (man 3 va_end) va_copy (man 3 va_copy) va_arg (man 3 va_arg)
I eargerly awaits opinions and help from anyone
root@d7c2d5297d9c:~/printf# cat main.h
#ifndef MAIN_H
#define MAIN_H
#define BUFFER_SIZE 1024
#include <stdarg.h>
#include <unistd.h>
#include <stdlib.h>
int _printf(const char *format, ...);
int _putchar(char c);
void print_null(void);
int print_char(va_list args);
int print_string(va_list args);
int print_percent(void);
int handle_default(void);
int print_int(va_list args);
int print_specifier(va_list args, char specifier);
int _snprintf(char *str, size_t size, const char *format, ...);
int process_format(char *str, size_t size, const char *format, va_list args);
void _puts(char *str);
#endif /* MAIN_H */
root@d7c2d5297d9c:~/printf# cat *.c
#include "main.h"
/**
* handle_default - handle case when specifiers not recognized
* Return: 2
*/
int handle_default(void)
{
_putchar('%');
return (2);
}
#include <limits.h>
#include <stdio.h>
#include "main.h"
/**
* main - Entry point
*
* Return: Always 0
*/
int main(void)
{
int len;
int len2;
unsigned int ui;
void *addr;
len = _printf("Let's try to printf a simple sentence.\n");
len2 = printf("Let's try to printf a simple sentence.\n");
ui = (unsigned int)INT_MAX + 1024;
addr = (void *)0x7ffe637541f0;
_printf("Length:[%d, %i]\n", len, len);
printf("Length:[%d, %i]\n", len2, len2);
_printf("Negative:[%d]\n", -762534);
printf("Negative:[%d]\n", -762534);
_printf("Unsigned:[%u]\n", ui);
printf("Unsigned:[%u]\n", ui);
_printf("Unsigned octal:[%o]\n", ui);
printf("Unsigned octal:[%o]\n", ui);
_printf("Unsigned hexadecimal:[%x, %X]\n", ui, ui);
printf("Unsigned hexadecimal:[%x, %X]\n", ui, ui);
_printf("Character:[%c]\n", 'H');
printf("Character:[%c]\n", 'H');
_printf("String:[%s]\n", "I am a string !");
printf("String:[%s]\n", "I am a string !");
_printf("Address:[%p]\n", addr);
printf("Address:[%p]\n", addr);
len = _printf("Percent:[%%]\n");
len2 = printf("Percent:[%%]\n");
_printf("Len:[%d]\n", len);
printf("Len:[%d]\n", len2);
_printf("Unknown:[%r]\n");
printf("Unknown:[%r]\n");
return (0);
}
#include "main.h"
/**
* print_char - Print a single character
* @args: The character to print.
* Return: Number of characters printed.
*/
int print_char(va_list args)
{
_putchar(va_arg(args, int));
return (1);
}
#include "main.h"
/**
* _printf - a custom printf function
* By: Sina
* @format: argument
* @...: another argument
* Return: The number of character printed
*/
int _printf(const char *format, ...)
{
va_list args;
int printed_chars;
char output_buffer[BUFFER_SIZE];
va_start(args, format);
printed_chars = process_format(output_buffer, BUFFER_SIZE, format, args);
va_end(args);
write(1, output_buffer, printed_chars);
return (printed_chars);
}
#include "main.h"
/**
* print_int - Prints out integers
* @args: Takes argument
* Return: printed_chars
* By: Sina Mathew
*/
int print_int(va_list args)
{
int i;
int num = va_arg(args, int);
char num_str[BUFFER_SIZE];
int printed_chars = _snprintf(num_str, BUFFER_SIZE, "%d", num);
for (i = 0; i < printed_chars; i++)
_putchar(num_str[i]);
return (printed_chars);
}
#include "main.h"
/**
* print_null - prints "(null)" to standard output.
* By Sina Mathew
*/
void print_null(void)
{
char null[] = "(null)";
int j;
for (j = 0; null[j] != '\0'; j++)
{
_putchar(null[j]);
}
}
#include "main.h"
/**
* print_percent - Print a percent character.
* Return: Number of characters printed
*/
int print_percent(void)
{
_putchar('%');
return (1);
}
#include "main.h"
/**
* print_string - Print a string.
* @args: The va_list containing the argument
* Return: Number of characters printed
*/
int print_string(va_list args)
{
char *s = va_arg(args, char *);
if (s != NULL)
{
int printed_chars = 0;
while (*s)
{
_putchar(*s);
s++;
printed_chars++;
}
return (printed_chars);
}
else
{
print_null();
return (6);
}
}
#include "main.h"
/**
* process_format - process and print the format string
* @format: Format string
* @args: Argument string
* @str: output string buffer
* @size: size of the buffer
* Return: Total number of character printed
* By: Sina Mathew
*/
int process_format(char *str, size_t size, const char *format, va_list args)
{
int printed_chars = 0;
size_t i = 0;
size_t j;
size_t str_len = 0;
char *temp_buffer = (char *)malloc(size);
if (temp_buffer == NULL)
return (-1);
while (format[i] != '\0' && str_len < size - 1)
{
if (format[i] != '%')
{
temp_buffer[str_len] = format[i];
str_len++;
i++;
}
else
{
i++;
printed_chars += print_specifier(args, format[i]);
if (printed_chars < 0)
{
free(temp_buffer);
return (-1);
}
str_len += 1;
i++;
}
}
for (j = 0; j < str_len; j++)
str[j] = temp_buffer[j];
str[str_len] = '\0';
free(temp_buffer);
return (str_len);
}
#include "main.h"
/**
* print_specifier - Print the specified type of data
* @args: Argument list
* @specifier: Current specifier character
* Return: Number of characters printed
*/
int print_specifier(va_list args, char specifier)
{
int printed_chars = 0;
switch (specifier)
{
case 'd':
printed_chars = print_int(args);
break;
case 'i':
printed_chars = print_int(args);
break;
case 'c':
printed_chars = print_char(args);
break;
case 's':
printed_chars = print_string(args);
break;
case '%':
printed_chars = print_percent();
break;
default:
printed_chars = handle_default();
break;
}
return (printed_chars);
}
#include "main.h"
/**
* _putchar - prints out character
* @c: store the value of the character
* Return: c
* By: Sina Mathew
*/
int _putchar(char c)
{
return (write(1, &c, 1));
}
#include "main.h"
/**
* _puts - prints a string to stdout
* @str: the string to print
* By: Sina Mathew
*/
void _puts(char *str)
{
size_t i = 0;
while (str[i] != '\0')
{
_putchar(str[i]);
i++;
}
}
#include "main.h"
/**
* _snprintf - custom snprintf
* @str: output string buffer
* @format: format string
* @size: size of the buffer
* @...: argument for format
* By: Sina Mathew
* Return: result, the number of characters printed.
*/
int _snprintf(char *str, size_t size, const char *format, ...)
{
va_list args;
int result = 0;
va_start(args, format);
result = process_format(str, size, format, args);
va_end(args);
return (result);
}
root@d7c2d5297d9c:~/printf# gcc -Wall -Wextra -Werror -pedantic -std=gnu89 -Wno-format *.c -o test
root@d7c2d5297d9c:~/printf# ./test
Let's try to printf a simple sentence.
Let's try to printf a simple sentence.
Segmentation fault (core dumped)
root@d7c2d5297d9c:~/printf# gcc -g -Wall -Wextra -Werror -pedantic -std=gnu89 -Wno-format *.c -o test
varoot@d7c2d5297d9c:~/printf# valgrind ./test
==4994== Memcheck, a memory error detector
==4994== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==4994== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==4994== Command: ./test
==4994==
Let's try to printf a simple sentence.
Let's try to printf a simple sentence.
==4994== Stack overflow in thread #1: can't grow stack to 0x1ffe801000
==4994==
==4994== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==4994== Access not within mapped region at address 0x1FFE801FF8
==4994== Stack overflow in thread #1: can't grow stack to 0x1ffe801000
==4994== at 0x1097C3: process_format (processFormat.c:14)
==4994== If you believe this happened as a result of a stack
==4994== overflow in your program's main thread (unlikely but
==4994== possible), you can try to increase the size of the
==4994== main thread stack using the --main-stacksize= flag.
==4994== The main thread stack size used in this run was 8388608.
==4994== Stack overflow in thread #1: can't grow stack to 0x1ffe801000
==4994==
==4994== Process terminating with default action of signal 11 (SIGSEGV)
==4994== Access not within mapped region at address 0x1FFE801FD8
==4994== Stack overflow in thread #1: can't grow stack to 0x1ffe801000
==4994== at 0x4831134: _vgnU_freeres (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_core-amd64-linux.so)
==4994== If you believe this happened as a result of a stack
==4994== overflow in your program's main thread (unlikely but
==4994== possible), you can try to increase the size of the
==4994== main thread stack using the --main-stacksize= flag.
==4994== The main thread stack size used in this run was 8388608.
==4994==
==4994== HEAP SUMMARY:
==4994== in use at exit: 5,706,752 bytes in 5,573 blocks
==4994== total heap usage: 5,574 allocs, 1 frees, 5,707,776 bytes allocated
==4994==
==4994== LEAK SUMMARY:
==4994== definitely lost: 0 bytes in 0 blocks
==4994== indirectly lost: 0 bytes in 0 blocks
==4994== possibly lost: 0 bytes in 0 blocks
==4994== still reachable: 5,706,752 bytes in 5,573 blocks
==4994== suppressed: 0 bytes in 0 blocks
==4994== Rerun with --leak-check=full to see details of leaked memory
==4994==
==4994== For lists of detected and suppressed errors, rerun with: -s
==4994== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
root@d7c2d5297d9c:~/printf# gdb test
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from test...
(gdb) run
Starting program: /root/printf/test
warning: Error disabling address space randomization: Operation not permitted
Let's try to printf a simple sentence.
Let's try to printf a simple sentence.
Program received signal SIGSEGV, Segmentation fault.
0x000055bc1f7b67c3 in process_format (str=<error reading variable: Cannot access memory at address 0x7ffe2837eff8>,
size=<error reading variable: Cannot access memory at address 0x7ffe2837eff0>,
format=<error reading variable: Cannot access memory at address 0x7ffe2837efe8>,
args=<error reading variable: Cannot access memory at address 0x7ffe2837efe0>) at processFormat.c:14
14 {
(gdb)
I tried everything i could, asked ChatGBT, read blogs about this issue, but i still dont understand where the problem is.
code must be compile with gcc -Wall -Wextra -Werror -pedantic -std=gnu89 -Wno-format *.c
I will be glad if anyone can help here, This is my first time using stackoverflow.
Solution
_printf
calls process_format
which calls print_specifier
which calls print_int
which calls _snprintf
which calls process_format
, thus forming a never-ending call loop.
You need to break that chain. Those functions should be designed as a tree, with higher-level routines (closer to the root) calling only lower-level routines. There should be no loop.
Answered By - Eric Postpischil Answer Checked By - Mildred Charles (WPSolving Admin)