Venant d'un Java background j'apprends le C, mais je trouve ces messages d'erreur du compilateur vagues 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] != '\0'; iTeller++)
cString[iTeller] = (char)tolower(cString[iTeller]);
return cString;
}
Cela génère deux avertissements.
Quelqu'un peut-il expliquer ces avertissements?
Les chaînes C ne ressemblent en rien aux 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'affectez à un char [] qui est un pointeur. D'où "conversion d'un entier en pointeur".
Votre strToLower effectue tous ses changements sur place, il n'y a aucune raison pour qu'il retourne quoi que ce soit, surtout pas un caractère. Vous devez "retourner" vide, ou un caractère *.
Lors de l'appel à strToLower, il n'y a pas non plus besoin d'affectation, vous passez essentiellement l'adresse de mémoire pour cString1.
D'après mon expérience, les chaînes en C sont la partie la plus difficile à apprendre pour quiconque venant de l'arrière-plan Java/C # vers C. Les gens peuvent s'entendre avec l'allocation de mémoire (car même en Java vous allouez souvent des tableaux Si votre objectif final est C++ et non C, vous préférerez peut-être moins vous concentrer 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 renvoyer cString
(qui est un char *
valeur dans ce contexte - un pointeur) à partir d'une fonction qui est déclarée renvoyer un char
(qui est un entier). Dans un autre cas, vous faites l'inverse: vous assignez une valeur de retour char
à une char *
pointeur. C'est ce qui déclenche les avertissements. Vous devez certainement déclarer vos valeurs de retour comme char *
, pas comme char
.
Notez BTW que ces affectations sont en fait violations de contraintes du point de vue du langage (c'est-à-dire que 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 également noter, c'est que dans plusieurs réponses, vous remarquerez peut-être la suggestion relativement étrange de renvoyer void
de vos fonctions, puisque vous modifiez la chaîne en place. Bien que cela fonctionnera certainement (puisque vous modifiez en effet la chaîne sur place), il n'y a rien de mal à retourner la même valeur à partir 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
me semblent complètement superflues (même si elles ne cassent rien). Je m'en débarrasserais
int compareString(char cString1[], char cString2[]) {
// To lowercase
strToLower(cString1);
strToLower(cString2);
// Do regular strcmp
return strcmp(cString1, cString2);
}
ou utilisez le "chaînage" et faites
int compareString(char cString1[], char cString2[]) {
return strcmp(strToLower(cString1), strToLower(cString2));
}
(c'est lorsque votre char *
le retour serait utile). Gardez à l'esprit que de tels appels de fonction "chaînés" sont parfois difficiles à déboguer avec un débogueur pas à pas.
Pour ajouter une note supplémentaire, je dirais que l'implémentation d'une fonction de comparaison de chaînes d'une manière aussi destructrice (elle modifie les chaînes d'entrée) pourrait ne pas être la meilleure idée. Une fonction non destructive aurait 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îne personnalisée, char par char, insensible à la casse et de l'utiliser au lieu d'appeler la norme strcmp
.
1) N'utilisez pas gets
! Vous introduisez une vulnérabilité de dépassement de tampon. Utilisez à la place fgets(..., stdin)
.
2) Dans strToLower
, vous retournez un tableau char
au lieu d'un tableau char
-. Soit retourner char*
comme suggéré automatiquement, ou renvoyez simplement void
puisque vous modifiez quand même l'entrée. En conséquence, écrivez simplement
strToLower(cString1);
strToLower(cString2);
strcasecmp
(Linux et Mac) ou stricmp
(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 dus au fait que vous renvoyez un caractère et que vous l'affectez à un caractère [] (ce qui équivaut à caractère *)
Vous renvoyez char, et non char *, qui est le pointeur sur le premier caractère d'un tableau.
Si vous souhaitez renvoyer un nouveau tableau de caractères au lieu d'effectuer une modification sur place, vous pouvez demander un pointeur (char *) déjà alloué 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 n'oubliez pas que dans les paramètres C transmis par la valeur TOUJOURS, vous devez donc utiliser char ** comme paramètre dans le cas d'un tableau alloué en interne par fonction. Bien sûr, l'appelant doit libérer ce pointeur plus tard.
strToLower doit renvoyer un caractère * au lieu d'un caractère. Quelque chose comme ça ferait l'affaire.
char *strToLower(char *cString)