L'affectation rend le pointeur à partir d'un entier sans conversion
Venant D'un arrière-plan Java, j'apprends C, mais je trouve ces vagues messages d'erreur du compilateur de plus en plus frustrants. Voici mon code:
/*
* PURPOSE
* Do case-insensetive string comparison.
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int compareString(char cString1[], char cString2[]);
char strToLower(char cString[]);
int main() {
// Declarations
char cString1[50], cString2[50];
int isEqual;
// Input
puts("Enter string 1: ");
gets(cString1);
puts("Enter string 2: ");
gets(cString2);
// Call
isEqual = compareString(cString1, cString2);
if (isEqual == 0)
printf("Equal!n");
else
printf("Not equal!n");
return 0;
}
// WATCH OUT
// This method *will* modify its input arrays.
int compareString(char cString1[], char cString2[]) {
// To lowercase
cString1 = strToLower(cString1);
cString2 = strToLower(cString2);
// Do regular strcmp
return strcmp(cString1, cString2);
}
// WATCH OUT
// This method *will* modify its input arrays.
char strToLower(char cString[]) {
// Declarations
int iTeller;
for (iTeller = 0; cString[iTeller] != ''; iTeller++)
cString[iTeller] = (char)tolower(cString[iTeller]);
return cString;
}
Cela génère deux avertissements.
- l'affectation crée un pointeur à partir d'un entier sans conversion
- cString1 = strToLower(cString1);
- cString2 = strToLower(cString2);
- return rend entier à partir du pointeur sans conversion
- renvoie cString;
Quelqu'un peut-il expliquer ces mises en garde?
8 réponses
Les chaînes C ne ressemblent pas à des chaînes Java. Ce sont essentiellement des tableaux de caractères.
Vous obtenez l'erreur car strToLower renvoie un caractère. Un char est une forme d'entier en C. Vous l'assignez dans un char [] qui est un pointeur. D'où "convertir un entier en pointeur".
Votre strToLower fait toutes ses modifications en place, il n'y a aucune raison pour qu'il retourne quoi que ce soit, surtout pas un char. Vous devriez "retourner" void, ou un char*.
Sur l'appel à strToLower, il n'y a pas non plus besoin d'affectation, vous ne faites que passer l'adresse mémoire pour cString1.
Dans mon expérience, les chaînes en C sont la partie la plus difficile à apprendre pour quiconque vient de Java/C# background vers C. Les gens peuvent s'entendre avec l'allocation de mémoire (puisque même en Java, vous allouez souvent des tableaux). Si votre objectif final est C++ et non C, vous préférerez peut-être vous concentrer moins sur les chaînes C, assurez-vous de comprendre les bases et utilisez simplement la chaîne C++ de STL.
Le type de retour de StrToLower doit être char*
pas char
(ou il ne devrait rien retourner du tout, car il ne ré-alloue pas la chaîne)
Comme d'autres l'ont déjà noté, dans un cas, vous essayez de retourner cString
(qui est une valeur char *
dans ce contexte-un pointeur) à partir d'une fonction déclarée pour retourner un char
(qui est un entier). Dans un autre cas, vous faites l'inverse: vous attribuez une valeur de retour char
à un pointeur char *
. C'est ce qui déclenche les avertissements. Vous devez certainement déclarer vos valeurs de retour comme char *
, pas comme char
.
Notez que ces affectations sont en fait une contrainte violations du point de vue de la langue (c'est-à-dire ce sont des "erreurs"), car il est illégal de mélanger des pointeurs et des entiers en C comme ça (à part la constante intégrale zéro). Votre compilateur est tout simplement trop indulgent à cet égard et signale ces violations comme de simples "Avertissements".
Ce que je voulais aussi noter, c'est que dans plusieurs réponses, vous remarquerez peut-être la suggestion relativement étrange de retourner void
de vos fonctions, puisque vous modifiez la chaîne sur place. Alors qu'il est le certainement travailler (puisque vous modifiez en effet la chaîne sur place), il n'y a rien de vraiment mal à renvoyer la même valeur de la fonction. En fait, c'est une pratique plutôt standard en langage C le cas échéant (jetez un oeil aux fonctions standard comme strcpy
et autres), car elle permet le "chaînage" des appels de fonction si vous choisissez de l'utiliser, et ne coûte pratiquement rien si vous n'utilisez pas le "chaînage".
Cela dit, les affectations dans votre implémentation de compareString
regardent complet superflu pour moi (même s'ils ne casseront rien). Soit je me débarrasse d'eux
int compareString(char cString1[], char cString2[]) {
// To lowercase
strToLower(cString1);
strToLower(cString2);
// Do regular strcmp
return strcmp(cString1, cString2);
}
Ou utilisez "chaînage" et faites
int compareString(char cString1[], char cString2[]) {
return strcmp(strToLower(cString1), strToLower(cString2));
}
(c'est à ce moment que votre retour char *
serait utile). Gardez simplement à l'esprit que de tels appels de fonction "enchaînés" sont parfois difficiles à déboguer avec un débogueur étape par étape.
En tant que note supplémentaire et irréelle, je dirais que l'implémentation d'une fonction de comparaison de chaînes de manière si destructrice (elle modifie l'entrée strings) pourrait ne pas être la meilleure idée. Une fonction non destructive serait d'une valeur beaucoup plus grande à mon avis. Au lieu d'effectuer une conversion explicite des chaînes d'entrée en minuscules, il est généralement préférable d'implémenter une fonction de comparaison de chaînes personnalisées non sensibles à la casse et de l'utiliser au lieu d'appeler la norme strcmp
.
1) Ne pas utiliser
gets
! Vous introduisez une vulnérabilité de dépassement de tampon. Utilisezfgets(..., stdin)
à la place.-
2) Dans
strToLower
, vous êtes de retour d'unchar
au lieu dechar
-tableau. Soit return {[6] } comme suggéré par Autopulated, soit returnvoid
puisque vous modifiez l'entrée de toute façon. Par conséquent, il suffit d'écrire
strToLower(cString1);
strToLower(cString2);
- 3) pour comparer les chaînes insensibles à la casse, vous pouvez utiliser
strcasecmp
(Linux et Mac) oustricmp
(Windows).
Vous n'avez pas besoin de ces deux affectations:
cString1 = strToLower(cString1);
cString2 = strToLower(cString2);
Vous modifiez les chaînes en place.
Les Avertissements sont parce que vous renvoyez un char, et l'affectation à un char [] (qui est équivalent à char*)
Vous renvoyez char, et non char*, qui est le pointeur vers le premier caractère d'un tableau.
Si vous voulez retourner un nouveau tableau de caractères au lieu de faire une modification sur place, vous pouvez demander un pointeur déjà alloué (char*) comme paramètre ou un pointeur non initialisé. Dans ce dernier cas, vous devez allouer le nombre approprié de caractères pour la nouvelle chaîne et rappelez-vous que dans les paramètres C transmis par la valeur toujours, vous devez donc utiliser char * * comme paramètre dans le cas du tableau alloué en interne par fonction. Bien sûr, l'appelant doit libérer ce pointeur plus tard.
StrToLower devrait renvoyer un char * au lieu d'un char. Quelque chose comme ce serait le faire.
char *strToLower(char *cString)
char cString1[]
Ceci est un tableau, c'est à dire un pointeur vers le premier élément d'une série d'éléments du même type de données. Notez que vous ne passez pas le tableau par valeur mais par pointeur.
char strToLower(...)
Cependant, cela renvoie un caractère. Donc, votre mission
cString1 = strToLower(cString1);
A différents types de chaque côté de l'opérateur d'affectation .. vous assignez en fait un ' char '(sorte d'entier) à un tableau, qui se résout en un simple pointeur. En raison des règles de conversion implicites de C++, cela fonctionne, mais le résultat est ordures et un accès supplémentaire au tableau provoque un comportement indéfini.
La solution consiste à faire strToLower
return char*
.