C语言 自定义printf函数分段错误

ni65a41a  于 2023-10-16  发布在  其他
关注(0)|答案(1)|浏览(103)

有谁能帮我完成这个项目吗?
我将在C语言课后建立一个自定义的printf函数。
我被限制使用大多数标准C函数。
必须遵循阿姨贝蒂编码风格和下面是授权的功能和宏
写(man 2写)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)
我急切地等待任何人的意见和帮助

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)

我试了一切我可以,问ChatGBT,阅读有关这个问题的博客,但我仍然不明白问题在哪里。代码必须使用gcc -Wall -Wextra -Werror -pedantic -std=gnu89 -Wno-format *.c编译
我会很高兴,如果有人可以帮助这里,这是我第一次使用stackoverflow。

xn1cxnb4

xn1cxnb41#

_printf调用process_formatprocess_format调用print_specifierprint_specifier调用print_intprint_int调用_snprintf_snprintf调用process_format,这样就形成了一个无休止的调用循环。
你必须打破这个链条。这些函数应该被设计成一棵树,高级例程(更接近根)只调用低级例程。不应该有循环。

相关问题