warum scheitert printf()?

Schnelle objektorientierte, kompilierende Programmiersprache.
Antworten
powerschaf
Beiträge: 13
Registriert: Mi Dez 13, 2017 10:41 am

warum scheitert printf()?

Beitrag von powerschaf » Do Jan 11, 2018 8:04 pm

Ich hab probiert wie doof...

Code: Alles auswählen

int main()
{
    char *y = NULL;
    printf("%s",y); /**geht**/

    char *i = "Hallo";
    strcpy(i, NULL);
    printf("%s",i); /**gehtnicht**/

}
Warum scheitert die printf() Ausgabe hier?
THX

powerschaf
Beiträge: 13
Registriert: Mi Dez 13, 2017 10:41 am

Re: warum scheitert printf()?

Beitrag von powerschaf » Do Jan 11, 2018 8:25 pm

Falls Jemand wissen möchte wozu ich es brauche.....
Klappt alles bis auf die Fehlrmldung und ich hab mir echt Müh geben :x

Code: Alles auswählen

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <windows.h>

// Wandelt einen gegebenen String in Großbuchstaben um.

void toUpperString(char *str)
{
    int i = 0;
    while (str[i])
    {
        putchar(toupper(str[i]));
        i++;
    }

}


// Wandelt einen gegebenen String in Kleinbuchstaben um.
void toLowerString(char *str)
{
    int i = 0;
    while (str[i])
    {
        putchar(tolower(str[i]));
        i++;
    }

}


// Wandelt Groß- in Kleinbuchstaben um und umgekehrt.
void toInverseString(char *str)
{
    int i = 0;
    while (str[i])
    {
        if (isupper(str[i]))
        {
            putchar(tolower(str[i]));
        }
        else
        {
            putchar(toupper(str[i]));
        }
        i++;
    }

    }

/** Konvertiert einen String sicher mittels einer gegebenen
Funktion. Ist der String str NULL, wird eine Fehlermeldung ausgegeben.
Ansonsten wird der String ausgegeben, mittels der gegebenen Funktion
konvertiert und dann wird der String ausgegeben.**/

void safeStringConverter(char* str, void (*conversionFunc)(char*))
{
    if (str == NULL)
    {
        printf("FEHLER");
        return;
    }

    else
    {
        printf("Stringname: %s\n",str);

    }

    if (conversionFunc == toUpperString)
    {
        toUpperString(str);
    }
    else if (conversionFunc == toLowerString)
    {
        toLowerString(str);
    }
    else if (conversionFunc == toInverseString)
    {
    toInverseString(str);
    }
    else
    {
        printf("FEHLER, Funktion nicht gefunden!");
        return;
    }




}

// Hauptprogramm

int main(int argc, const char * argv[])
{
    char s[64];

    printf("----------------------------------\n");
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),4);
    printf("Test(1) toUpperString:\n");
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),15);
    strcpy(s, "Ich muss noch wachsen");
    safeStringConverter(s, toUpperString);
    printf("\n----------------------------------\n\n");


    printf("----------------------------------\n");
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),4);
    printf("Test(2) toLowerString:\n");
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),15);
    strcpy(s, "HILFE ICH BIN ZU GROSS");
    safeStringConverter(s, toLowerString);
    printf("\n----------------------------------\n\n");

    printf("----------------------------------\n");
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),4);
    printf("Test(3) toInverseString:\n");
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),15);
    strcpy(s, "TAUSCHE mich");
    safeStringConverter(s, toInverseString);
    printf("\n----------------------------------\n\n");

     printf("----------------------------------\n");
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),4);
    printf("FEHLERPARAMTER TEST: \n");
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),15);
    strcpy(s,NULL);
    safeStringConverter(s, toUpperString);




    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),15);

    return EXIT_SUCCESS;
}

nufan
Wiki-Moderator
Beiträge: 2557
Registriert: Sa Jul 05, 2008 3:21 pm

Re: warum scheitert printf()?

Beitrag von nufan » Do Jan 11, 2018 11:56 pm

powerschaf hat geschrieben:

Code: Alles auswählen

    strcpy(i, NULL);
Warum scheitert die printf() Ausgabe hier?
Die printf()-Ausgabe scheitert nicht, sondern strcpy(). Du übergibst NULL als Quell-String für den Kopiervorgang. Die Funktion versucht an dieser Stelle Daten zu lesen und das Programm stürzt ab.

Du kannst das ganze unter Linux auch mit valgrind debuggen:

Code: Alles auswählen

$ valgrind ./a.out
[...]
==2901== Invalid read of size 1
==2901==    at 0x4F7D260: __strcpy_ssse3 (in /usr/lib/libc-2.26.so)
==2901==    by 0x1086DD: main (in /tmp/a.out)
==2901==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
[...]

powerschaf
Beiträge: 13
Registriert: Mi Dez 13, 2017 10:41 am

Re: warum scheitert printf()?

Beitrag von powerschaf » Fr Jan 12, 2018 8:36 am

Ja habe die Lösung... ich übergebe NULL direkt in der Funktion safeStringcopy(NULL, funktion)... das strcpy fällt weg.

mfro
Beiträge: 346
Registriert: Mi Jan 16, 2013 4:58 pm

Re: warum scheitert printf()?

Beitrag von mfro » Fr Jan 12, 2018 10:57 am

powerschaf hat geschrieben:

Code: Alles auswählen

...
    if (conversionFunc == toUpperString)
    {
        toUpperString(str);
    }
    else if (conversionFunc == toLowerString)
    {
        toLowerString(str);
    }
    else if (conversionFunc == toInverseString)
    {
    toInverseString(str);
    }
    else
    {
        printf("FEHLER, Funktion nicht gefunden!");
        return;
    }
Wozu soll das gut sein? Wenn Du nur *genau die* Stringkonvertierungen zulassen willst, macht es keinen Sinn, einen Funktionszeiger zu übergeben (der ist ja gerade dazu gedacht, eine Funktion aufrufen zu können, an die beim Entwurf noch nicht gedacht war). Wenn das also eingeschränkt sein soll, wäre so was hier m.E. besser:

Code: Alles auswählen

enum conversion { TOUPPER, TOLOWER, TOINVERSE } cv;

void safeStringConverter(char* str, enum conversion cv)
{
    switch (cv)
    {
        case TOUPPER:
            toUpperStr(str);
            break;
       case TOLOWER:
            toLowerStr(str);
            break;
    ....
    }
}
Wenn Du dir hingegen die Flexibilität erhalten willst, neue Konvertierungen hinzuzufügen ohne existierenden Code ändern zu müssen, solltest Du direkt den Funktionszeiger aufrufen:

Code: Alles auswählen

    if (conversionFunc)
       (*conversionFunc)(str);
und dem Aufrufer vertrauen, dass er eine vernünftige Funktion bereitstellt. Deins ist eine Mischung aus beidem (und vereint m.E. die Nachteile), jeder, der das liest wird sich fragen: was macht er denn da?
It's as simple as that. And remember, Beethoven wrote his first symphony in C.

Antworten