Frage

Ich benutze Linux. Ich versuche, ein Programm in C zu schreiben, das eine Zeichenfolge rückwärts druckt. Hier ist mein Code:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (){
    char string[100];
    printf ("Enter string:\n");
    gets (string);
    int length = strlen (string)-1;
    for (length = length; length>=0; length--){
        puts (string[length]);
    }
}

Und hier ist der Fehler:

a.c:10: warning: passing argument 1 of ‘puts’ makes pointer from integer without a cast
/usr/include/stdio.h:668: note: expected ‘const char *’ but argument is of type ‘char’
/tmp/cc5rpeG7.o: In function `main':
a.c:(.text+0x29): warning: the `gets' function is dangerous and should not be used.

Was soll ich machen?

War es hilfreich?

Lösung

Zuerst:

Nie nie nie nie verwenden gets(); es Wille Führen Sie einen Ausfallpunkt in Ihrem Code ein. Es gibt keine Möglichkeit zu sagen gets() Wie groß der Zielpuffer ist. Wenn Sie also einen Puffer -Größe übergeben, um 10 Zeichen zu halten, und im Eingabestream 100 Zeichen enthalten, befinden sich dies. gets() speichert diese zusätzlichen 90 Zeichen in der Erinnerung über das Ende Ihres Puffers und klopft möglicherweise etwas Wichtiges. Pufferüberschreitungen sind ein einfacher Malware -Exploit. Der Morris -Wurm nutzte speziell a gets() Rufen Sie sendmail an.

Verwenden fgets() stattdessen; Sie können die maximale Anzahl von Zeichen angeben, die Sie aus dem Eingabestream lesen können. Im Gegensatz zu gets(), fgets() speichert den Kündigungs -Newline -Charakter dem Puffer, wenn es Platz dafür gibt. Daher müssen Sie dazu berücksichtigen:

char string[100]; 
char *newline;
printf("Enter a string: ");
fflush(stdout);
fgets(string, sizeof string, stdin);
newline = strchr(buffer, '\n');      // search for the newline character
if (newline)                         // if it's present
  *newline = 0;                      // set it to zero

Nun, das ist aus dem Weg ...

Ihr Fehler kommt von der Tatsache, dass puts() erwartet ein Argument vom Typ char *, aber du passierst ein Argument vom Typ char, daher der "Zeiger von Ganzzahl ohne Besetzung" (Botschaft "char ist ein integraler Typ). Um ein einzelnes Zeichen in Stdout zu schreiben, verwenden Sie putchar() oder fputc().

Andere Tipps

Vergessen Sie, dass die Funktion gets() existiert - es ist tödlich. Verwenden fgets() Stattdessen (beachten Sie jedoch, dass die Neue Linie am Ende der Linie nicht entfernt wird).

Sie möchten jeweils ein einzelnes Zeichen setzen: Verwendung putchar() um es an stdout zu schreiben. Vergessen Sie nicht, nach der Schleife eine neue Zeile zur Ausgabe hinzuzufügen.

Ebenfalls, for (length = length; length >= 0; length--) ist nicht idiomatisch C. Verwenden Sie einen von:

  • for ( ; length >= 0; length--)
  • for (length = strlen(string) - 1; length >= 0; length--)
  • for (int length = strlen(string) - 1; length >= 0; length--)

Die letzte Alternative verwendet eine zu C99 hinzugefügte Funktion (die lange zuvor in C ++ erhältlich war).

Außerdem konnten wir diskutieren, ob length ist der entsprechende Name für die Variable. Es wäre besser in als umbenannt wie i oder pos oder ähnliches, weil es zwar auf die Länge der Eingabe initialisiert wird, es jedoch tatsächlich als Array -Index verwendet wird, nicht als Länge von irgendetwas.

Subjektiv: Platzieren Sie keinen Platz zwischen dem Namen einer Funktion und ihrer Parameterliste. Die Gründungsväter von C tun das nicht - auch nicht.


Warum wird () tödlich?

Der erste Internetwurm - der Morris Wurm von 1988 - nutzte das aus fingerd Programm, das verwendet wird gets() Anstatt von fgets(). Seitdem wurden zahlreiche Programme abgestürzt, weil sie verwendet wurden gets() und nicht fgets() oder eine andere Alternative.

Das grundlegende Problem ist das gets() weiß nicht, wie viel Platz zur Verfügung steht, um die von ihnen gelesenen Daten zu speichern. Dies führt zu "Pufferüberläufen", einem Begriff, nach dem in Ihrer bevorzugten Suchmaschine gesucht werden kann, die eine enorme Anzahl von Einträgen zurückgibt.

Wenn jemand 150 Zeichen Eingabe in das Beispielprogramm eingibt, dann gets() speichert 150 Zeichen im Array mit einer Länge 100. Dies führt nie zu Glück - es führt normalerweise zu einem Kern -Dump, aber mit sorgfältig ausgewählten Eingaben - oft erzeugt durch ein Perl- oder Python -Skript - können Sie wahrscheinlich das Programm zur Ausführung beliebiger Ausführung bringen Anderer Code. Dies ist wirklich wichtig, wenn das Programm jemals von einem Benutzer mit "erhöhten Berechtigungen" ausgeführt wird.

Übrigens, gets() wird wahrscheinlich in der nächsten Version aus der Standard -C -Bibliothek entfernt (C1X - siehe N1494 von WG14). Es wird noch lange nicht aus den tatsächlichen C -Bibliotheken verschwinden (20 Jahre?), Sollte aber durch diese Implementierung (oder ähnliches) ersetzt werden:

#undef NDEBUG
#include <assert.h>
char *gets(char *buffer)
{
    assert("Probability of using gets() safely" == 0);
}

Ein weiteres kleines Detail, das teilweise unter den Kommentaren zur Hauptfrage erörtert wird.

Der angezeigte Code ist eindeutig für C99; Die Erklärung von length Der Teil der Funktion ist in C89 ungültig. Angesichts dessen ist es für die "OK" main() Funktionen Sie nicht explizit einen Wert zurück, da der C99 -Standard dem Lead des C ++ - Standard main() und der Effekt ist der gleiche wie return(0); oder return 0; Am Ende.

Daher kann das Programm in dieser Frage nicht strikt dafür verantwortlich gemacht werden return Am Ende. Ich betrachte jedoch das als eine der besonderen standardisierenden Entscheidungen und würde sie sehr bevorzugen, wenn die Standards diese Bereitstellung verlassen hätten - oder etwas radikaleres wie das allgegenwärtige, aber fehlerhafte Erliegen gemacht haben void main() Beobachten Sie, dass bei der Rückkehr der Kontrolle das Ergebnis ist, dass ein Erfolgsstatus in die Umgebung zurückgeführt wird. Es ist nicht wert return aus main(). Wenn der Code mit C89 -Compilern zusammenarbeiten muss, sollte er den expliziten haben return 0; am Ende (aber dann die Erklärung von length muss auch repariert werden).

Sie können auch eine Rekursion verwenden. Ich denke, es sieht schöner aus als bei der Verwendung einer Schleife.

Rufen Sie einfach die Methode mit Ihrer Zeichenfolge an und drucken Sie das Zeichen in der Methode erneut mit der gleichen Zeichenfolge abzüglich des ersten Zeichens.

Dadurch wird Ihre Zeichenfolge in umgekehrter Reihenfolge ausgedruckt.

Du solltest benutzen putchar Anstatt von puts

Also diese Schleife:

for (length = length; length>=0; length--){
    puts (string[length]);
}

Wird sein:

for (length = length; length>=0; length--){
    putchar (string[length]);
}

putchar Nehmen Sie ein einzelnes Zeichen als Parameter und drucken Sie es drucken stdout, Was ist was du willst. puts, dagegen druckt die gesamte Zeichenfolge zu stdout. Wenn Sie also ein einzelnes Zeichen an eine Funktion übergeben, die eine ganze Zeichenfolge erwartet (Zeichenarray, NULL Kündigte Zeichenfolge), Compiler wird verwirrt.

Verwenden putc oder putchar, wie puts ist angegeben, um a zu nehmen char* und Sie füttern es a char.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top