passing argument makes pointer from integer without a cast - c

I've read through several similar questions on Stack Overflow, but I've not been able to find one that helps me understand this warning in this case. I'm in my first week of trying to learn C though, so apologies if I've missed an obvious answer elsewhere on Stack Overflow through lack of understanding.
I get the following warning and note:
warning: passing argument 2 of ‘CheckIfIn’ makes pointer from integer without a cast [enabled by default]
if(CheckIfIn(letter, *Vowels) ){
^
note: expected ‘char *’ but argument is of type ‘char’
int CheckIfIn(char ch, char *checkstring) {
When trying to compile this code:
#include <stdio.h>
#include <string.h>
#define CharSize 1 // in case running on other systems
int CheckIfIn(char ch, char *checkstring) {
int string_len = sizeof(*checkstring) / CharSize;
int a = 0;
for(a = 0; a < string_len && checkstring[a] != '\0'; a++ ){
if (ch == checkstring[a]) {
return 1;
}
}
return 0;
}
// test function
int main(int argc, char *argv[]){
char letter = 'a';
char *Vowels = "aeiou";
if(CheckIfIn(letter, *Vowels) ){
printf("this is a vowel.\n");
}
return 0;
}

Vowels is a char*, *Vowels is just a char, 'a'. chars get automatically promoted to integers, which your compiler is allowing to be implicitly converted to a pointer. However the pointer value will not be Vowels, it will be the address equal to the integer encoding of the character 'a', 0x61 almost universally.
Just pass Vowels to your function.

In your case, the type conversion is from char to integer pointer. In some cases, the function takes void pointer as the second argument to accommodate for all the data-types.
In such cases, you would need to typecast the second argument as (void *)
This would be the function declaration in most well written modular functions:
int CheckIfIn(char ch, void *checkstring);
You would need to pass the argument as a void pointer, provided the Vowels is not a char pointer
if(CheckIfIn(letter, (void *)Vowels) ){
printf("this is a vowel.\n");
}

Related

Comparing every char in a string to a constant

Sorry, I'm relatively new to c. What I'm trying to do is loop through a string and compare each char in the string to a char. If successful, I print some value. However I'm getting a segmentation fault.
My Code:
int i;
const char* perc = '%';
char mystr[7] = "hell%o";
for(i=0;i<sizeof(mystr);i++){
if(strcmp(mystr[i],perc)!=0){
printf("%d",i);
}
NOTE: I'm not using % for format strings here, I'm literally just looking for its position in the string.
Thank you.
strcmp() is for comparing strings. To compare characters, you can use == operator.
Also note that sizeof is not for getting length of strings but getting number of bytes used for the type. In this case it is used for char array, so it may work according to what you want to do because sizeof(char) is defined to be 1 and therefore the number of bytes will be equal to the number of elements. Note that the terminating null-character and unused elements after that will added to the count if they exists. To get the length of string, you should use the strlen() function.
int i;
const char perc = '%'; /* use char, not char* */
char mystr[7] = "hell%o";
int len = strlen(mystr); /* use strlen() to get the length of the string */
for(i=0;i<len;i++){
if(mystr[i] != perc){ /* compare characters */
printf("%d",i);
}
if(strcmp(mystr[i],perc)!=0){
Must be if(mystr[i]!= perc){. And const char* perc = '%'; should be const char perc = '%';
strcmp takes two strings (char*), but you are passing chars. Compiling with gcc and -Wall shows:
c.c: In function ‘main’:
c.c:5:20: warning: initialization of ‘const char *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
5 | const char* perc = '%';
| ^~~
c.c:9:24: warning: passing argument 1 of ‘strcmp’ makes pointer from integer without a cast [-Wint-conversion]
9 | if(strcmp(mystr[i],perc)!=0){
| ~~~~~^~~
| |
| char
In file included from c.c:1:
/usr/include/string.h:137:32: note: expected ‘const char *’ but argument is of type ‘char’
137 | extern int strcmp (const char *__s1, const char *__s2)
| ~~~~~~~~~~~~^~~~
Always remember: The compiler is one of the best friends of you.
The fixed program could be:
#include <stdio.h>
#include <string.h>
int main() {
int i;
const char perc = '%';
char mystr[7] = "hell%o";
for (i = 0; i < sizeof(mystr); i++) {
if (mystr[i] != perc) {
printf("%d", i);
}
}
}

Void pointers and dynamic memory allocation

I'm trying to make a word counter program that takes a sentence and counts the number of words. I would like to use dynamic memory allocation because it has many advantages such as not having to worry about not enough space or too much empty space. Here is my code so far:
#include <stdio.h>
#include <stdlib.h>
const char *strmalloc(const char *string);
char *user_input = NULL;
int main(void) {
printf("Enter a sentence to find out the number of words: ");
strmalloc(user_input);
return 0;
}
const char *strmalloc(const char *string) {
char *tmp = NULL;
size_t size = 0, index = 0;
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
if (size <= index) {
size += 1;
tmp = realloc((char*)string, size);
}
}
}
As you might know, the prototype for the realloc function goes like this:
void *realloc(void *ptr, size_t size)
When I use the realloc function in the while loop in the strmalloc() function, I get a warning saying:
Passing 'const char *' to parameter of type 'void *' discards qualifiers
I have no idea what this means but I know that I can get rid of it with a typecast to char*
However, I've learned that I shouldn't use a typecast just to prevent a warning. I should learn what the warning is warning me about and decide whether a typecast is the right thing. But then again, I know that a pointer to void accepts any data type, and to specify one, a typecast is required. So my question is, should I keep the typecast in the realloc() function or get rid of it and do something else.
const is a type qualifier. In the C and maybe in many other programming languages, const applied to a data type indicates that the data is read only.
Passing 'const char *' to parameter of type 'void *' discards qualifiers
The above error you are getting because you are passing const object to a parameter that is not const ( (void *) in realloc), and warning you about there is a possibility of changing (discards) the values pointed by const char* string by using void* ptr, that defeats the whole purpose of declaring the data as const.
But looking at the example, you are trying to allocate a memory for char* string, and after allocation, you would want to write something into that memory, if you make it const, how do expect it to write.
So you don't need your char* string to be const and hence , there is no need of cast to char* in realloc.

what is wrong in this strcmp()?

I try to write simple C function with strcmp(). But I always get Segmentation fault (core dumped). What is wrong ?
char *arr={"abcdefg"};
char *a = arr[1];
if(strcmp(a, 'b') == 0)
{
printf("it is b \n");
}
What is wrong?
You did not let yourself be helped by the compiler.
Using -Wall -Wextra on GCC (which is by no means the best you can get but rather the bare minimum you should always use), I get:
testme.c: In function ‘main’:
testme.c:6:11: warning: initialization makes pointer from integer without a cast [enabled by default]
char *a = arr[1];
^
You took arr[1] -- which is the char value 'b' -- and turned it into a char *. Your a is now pointing to whatever is at address 0x62 (assuming ASCII), which is most definitely not what you intended. You probably wanted &arr[1], or arr + 1.
Or you wanted a char -- then you shouldn't declare char *, and strcmp() would be the wrong thing to use in the first place.
testme.c:8:1: warning: passing argument 2 of ‘strcmp’ makes pointer from integer without a cast [enabled by default]
if(strcmp(a, 'b') == 0)
^
In file included from testme.c:1:0:
/usr/include/string.h:144:12: note: expected ‘const char *’ but argument is of type ‘int’
extern int strcmp (const char *__s1, const char *__s2)
^
strcmp() expects two C strings (char const *). Your second argument 'b' is of type int... you probably wanted "b".
Which still would not compare equal, because "bcdefg" is not equal "b"...
Or you wanted a one-character comparison... that would be if ( a == 'b' ) then, with a being of type char, not char * (see above).
testme.c:10:5: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
printf("it is b \n");
^
testme.c:10:5: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
Please do us all the favour of posting complete code, includes, int main() and all, so we can copy & paste & compile, and still have line numbers match.
I think this is what you have been trying to achieve :
#include <stdio.h>
#include <string.h>
int main(void)
{
char *arr = {"abcdefg"};
char a = arr[1];
if( a == 'b' )
{
printf("it is b \n");
}
}
You're doing a number of things wrong here. strcmp is for comparing strings. The simplest way to do what you want is
char *arr= {"abcdefg"};
char a = arr[1];
if(a == 'b')
{
printf("it is b \n");
}
If you still want to do it with strcmp, you need to make a a string by appending the null terminator \0 to it.
char *arr= {"abcdefg"};
char a[] = {arr[1], '\0'};
if(strcmp(a, "b") == 0)
{
printf("it is b \n");
}

C programming warning: array subscript has type 'char' [-Wchar-subscripts]

I can't seem to fix this problem. Below is my code:
#include<stdio.h>
#include<ctype.h>
#include<string.h>
_Bool are_anagrams (const char *word1, const char *word2);
int main (void)
{
char an1[30], an2[30];
int j;
printf("Enter first word: ");
scanf("%s", an1);
printf("Enter second word: ");
scanf("%s", an2);
printf("The words are");
j = are_anagrams (an1, an2);
if (j == 0)
{
printf(" not anagrams. \n");
}else
printf(" anagrams. \n");
return 0;
}
_Bool are_anagrams (const char *word1, const char *word2)
{
int i;
int check[26] = {0};
for(i=0; i<30; i++)
if(word1[i] == '\0')
i=40;
else
{
word1[i] = toupper(word1[i]);
check[word1[i]-65]++;
}
for(i=0; i<30; i++)
if(word2[i] == '\0')
i=40;
else
{
word2[i] = toupper(word2[i]);
check[word2[i]-65]--;
}
for(i=0; i<26; i++)
if(check[i] != 0)
{
return 0;
}
return 1;
}
these are the error messages:
anagram1.c:38:3: warning: array subscript has type ‘char’ [-Wchar-subscripts]
word1[i] = toupper(word1[i]);
^
anagram1.c:38:3: error: assignment of read-only location ‘*(word1 + (sizetype)((long unsigned int)i * 1ul))’
anagram1.c:46:4: warning: array subscript has type ‘char’ [-Wchar-subscripts]
word2[i] = toupper(word2[i]);
^
anagram1.c:46:4: error: assignment of read-only location ‘*(word2 + (sizetype)((long unsigned int)i * 1ul))’
The warnings:
warning: array subscript has type ‘char’
are a result of 'toupper()' requiring an 'int' type as a parameter, while the question code is providing a 'char' type.
word1[i] = toupper(word1[i]);
...
word2[i] = toupper(word2[i]);
To eliminate the warning, give toupper() 'int' values:
word1[i] = toupper((unsigned char)word1[i]);
...
word2[i] = toupper((unsigned char)word2[i]);
To be thorough, you can cast the values returned by 'toupper()' from 'int' back to 'char':
word1[i] = (char)toupper((unsigned char)word1[i]);
...
word2[i] = (char)toupper((unsigned char)word2[i]);
The errors:
error: assignment of read-only location
are a result of trying to modify a value with a 'const' flag:
_Bool are_anagrams (const char *word1, const char *word2)
If appropriate, you can eliminate the errors by eliminating the 'const' flags:
_Bool are_anagrams (char *word1, char *word2)
Or, you can make local-working copies of the 'const' strings:
_Bool are_anagrams (const char *I__word1, const char *I__word2)
{
int rCode = 0;
int i;
int check[26] = {0};
char *word1 = strdup(I__word1);
char *word2 = strdup(I__word2);
for(i=0; i<30; i++)
if(word1[i] == '\0')
i=40;
else
{
word1[i] = toupper(word1[i]);
check[word1[i]-65]++;
}
for(i=0; i<30; i++)
if(word2[i] == '\0')
i=40;
else
{
word2[i] = toupper(word2[i]);
check[word2[i]-65]--;
}
for(i=0; i<26; i++)
if(check[i] != 0)
goto CLEANUP;
rCode=1;
CLEANUP:
free(word2);
free(word1);
return(rCode);
}
NOTE: The above code uses the the question code body, which may or may not be accurate. This answer has no intention to fix other issues in the question code; only to demonstrate a proper method to work around the 'const' flags on the parameters by creating non-'const' copies of the parameters
The toupper and tolower functions declared in <ctype.h> (along with the is*() functions) expect an argument of type int.
The type isn't the problem, since char will be implicitly converted to int. The problem is that the value they expect must be either within the range of unsigned char or the value EOF (typically -1). We can ignore the EOF case.
Plain char is either signed or unsigned, at the whim of your compiler developer (guided by your system's ABI). If plain char is signed, and the value you pass to toupper happens to have a negative value (that doesn't happen to equal EOF), then you have undefined behavior.
The solution is to explicitly convert (cast) the argument to unsigned char.
Rather than:
word1[i] = toupper(word1[i]);
you need to write:
word1[i] = toupper((unsigned char)word1[i]);
Yes, it's unfortunate that you have to do this. It would be better if toupper() simply took an argument of type char and returned a char result. But this is the way it is, and we're stuck with it.
So why did you get a warning about an array subscript of type char? The toupper function is commonly implemented as a macro that expands to an array indexing operation. After the preprocessor expands the macro invocation, it no longer looks (to the rest of the compiler) like a function call. (Any standard library function can be implemented as a macro, as long as the macro has the same behavior that an actual function call would have.)
As Mahonri Moriancumer correctly identifies in his answer (and, indeed, as Keith Thompson correctly identified and explained in his answer), the problem with the calls to toupper() is that the type you're passing is char yet the functions expect an int. But since an int can contain any value that a char can contain, why is it complaining?
The answer is that the range of valid int values is restricted by the standard (ISO/IEC 9888:2011):
7.4 Character handling <ctype.h>
In all cases the argument is an int, the value of which shall be
representable as an unsigned char or shall equal the value of the macro EOF. If the
argument has any other value, the behavior is undefined.
What the compiler is warning you is that if you pass a char to this function, and if the char type is a signed type, then you may be passing an index that is negative. The result of getchar(), getc() or fgetc() matches the specification of the argument type for the functions (and this is not an accident). The compiler assumes you won't pass out of bounds values if you use an int, but if you use plain char to hold characters such as 'Å' (U+00C5, LATIN CAPITAL LETTER A WITH RING ABOVE) and plain char is signed, then you will be passing a negative value well outside the range of valid values.
If it were my code, I would cast to unsigned char:
word1[i] = toupper((unsigned char)word1[i]);
Simply casting a signed plain char to int doesn't deal with the sign properly.
You can review C isupper() function to understand more about why the ranges are set as they are.
The other pair of errors comes because you modify a constant string. You can avoid that error (for unaccented characters) with:
unsigned char uc = word1[i];
if (isalpha(uc))
check1[toupper(uc) - 'A']++;
This avoids problems with spaces, digits and punctuation in the input. However, if you need to deal with accented characters in the input, then your best bet is to make check into an array of size 256, and then check over the whole range 0..255 that the counts are the same.

'stripspaces' makes integer from pointer without cast

#include <stdio.h>
#include <ctype.h>
#define STRING_LEN 500
void stripspaces(char, char, char);
int main(void)
{
char string[STRING_LEN];
char *p1 = string;
char *p2 = string;
printf("Enter a string of up to %d characters:\n", STRING_LEN);
while((*p1++ = getchar()) != '\n') ;
stripspaces(string, *p1, *p2);
getch();
return 0;
}
void stripspaces (char s, char *x1, char *x2){
*x1 = '\0';
x1 = s;
while(*x1 != '\0')
{
if(ispunct(*x1) || isspace(*x1))
{
++x1;
continue;
}
else
*x2++ = *x1++;
}
*x2 = '\0';
printf("\nWith the spaces removed, the string is now:\n%s\n", s);
}
This code is bringing up the following error at the 'stripspaces' function; "passing arg 1 of 'stripspaces' makes integer from pointer without a cast" any help would be excellent.
In case it is not obvious from the code, the program should take in a string and remove all the spaces from it. The function has to remain although I know I can do it without the function.
Your prototype and function definition don't match:
void stripspaces(char, char, char);
vs.
void stripspaces (char s, char *x1, char *x2)
You should change the prototype to
void stripspaces(char, char*, char*);
And in order to make them both work, you should use
void stripspaces(char*, char*, char*);
and
void stripspaces (char *s, char *x1, char *x2)
.
For easier copy & paste, you can use parameter names in the prototype as well.
Both of the answers above are telling you that your function declaration is wrong. Also you are dereferencing pointers when passing them to the function.
stripspaces(string, *p1, *p2);
This turns the call into (char*, char, char) which is not right and will not behave as you expect it to. It is also the source of the particular compiler error you are seeing. The compiler is trying to fit the string(char*) into a char, and thus making an "integer from pointer without cast" since char is basically an 1 byte integer.
Correcting the function declaration would be step one, you want to pass all pointers or you won't be able to manipulate the string.
Fix the declaration and then call the function like this.
stripspaces(string, p1, p2);
You need to change the first argument from char s (single character) to char *s (pointer)

Resources