#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)
Related
I'm trying to figure out how to "transform" strings (char*) to void* and viceversa.
When I execute this my output is just the first printf and ignores the second one, it doesn't even write "after = "
PS This little program is just to understand, I know i could actually use swap(&s[0],&s[1]). I need to know how to properly cast a void pointer into an array of strings.
I'm working on a uni project where I need to create my own quick_sort algorythm and I need the swap function inside of it to work with void pointers.
#include <stdio.h>
#include <stdlib.h>
static void swap(char** x,char** y);
static void swap(char** x,char** y){
char* temp=*x;
*x=*y;
*y=temp;
}
int main()
{
char* s[2];
s[0]="weee";
s[1]="yooo";
void* array=s;
printf("before %s %s\n",s[0],s[1]);
swap((&array)[0],(&array)[1]);
printf("after = %s %s",(char*)array,(char*)array);
return 0;
}
I think I'm missing something big
Thanks in advance :D
In this declaration the array s used as an initializer is implicitly converted to a pointer to its first element of the type char **.
void* array = s;
In the call of the function swap
swap((&array)[0],(&array)[1]);
the first argument can be the pointer array itself that will be implicitly casted to the pointer type of the corresponding parameter
swap( array, (&array)[1]);
But you need to correctly pass the second argument. To do this you need to cast the pointer array explicitly like
swap( array, ( char ** )array + 1 );
In the call of printf you need also correctly to supply argument expressions.
Here is your updated program
#include <stdio.h>
static void swap(char** x,char** y);
static void swap(char** x,char** y){
char* temp=*x;
*x=*y;
*y=temp;
}
int main()
{
char* s[2];
s[0]="weee";
s[1]="yooo";
void* array=s;
printf("before %s %s\n",s[0],s[1]);
swap( array, ( char ** )array + 1 );
printf("after = %s %s", *(char**)array, ( (char**)array )[1]);
return 0;
}
The program output is
before weee yooo
after = yooo weee
void *array = s; declares array to be a void *. Then &array is the address of that void *, so &array[1] would access a void * after it. But there is no void * after it, since void *array defines a single void *.
array could be properly defined to alias s with char **array = s;, after which swap(&array[0], &array[1]); would work as desired.
If you define array as void **array = (void **) s;, then swap(&array[0], &array[1]); will produce diagnostic messages because the types are wrong. You could use swap((char **) &array[0], (char **) &array[1]);.
Then, if you print the strings with printf("after = %s %s", array[0], array[1]);, this will work, although it is not entirely proper code. Using array[0] as an argument passes a void * where printf is expecting a char * for the %s. However, the C standard guarantees that void * and char * have the same representation (encode their values using bytes in memory in the same way), and it further says (in a non-normative note) that this is intended to imply interchangeability as arguments to functions.
The void* doesn't seem to fulfil any particular purpose here, just swap the pointers: swap(&s[0],&s[1]);.
You could also do this:
char** ptr = &s[0];
printf("before %s %s\n",ptr[0],ptr[1]);
swap(&ptr[0],&ptr[1]);
printf("after = %s %s",ptr[0],ptr[1]);
If you for reasons unknown insist on using void* then note that as your code stands, it points at the first char* in your array of char*. However, it isn't possible to perform pointer arithmetic on void* since that would entail knowing how large a "void" is. The void* doesn't know that it points at an array of pointers. Therefore array[i] is nonsense.
Also, the void* are set to point at char* so you simply cannot pass it to a function expecting a char**. You'd have to rewrite the whole program in a needlessly obfuscated way, so just abandon that idea.
I have a midterm in Saturday, so our teacher gave us the previous year's midterm to help. So there is a problem that I have trouble to understand. The question is 'fill the question marks so that program outputs the string 'accioccium'.
For who do not want to spend on solving, the answers are 1,2 and spell2.
So what is happening here? Especially, what is char* (*a[3]) (char *, char *)? I mean we are creating a char pointer array but what is that paranthesis at the end?
Also, a[0] = fun1 is weird too. Yes, you can assign variables by functions. However, there is no parameter here for fun1 function. Let us say parameters are constant as *s and *p. But this time, what are they?
#include <stdio.h>
#include <string.h>
char* fun1(char *s, char *p) {
return s+strspn(s,p);}
char* fun2(char *s,char *p) {
return strcat(s,p);}
char* fun3(char *s,char *p){
return strstr(s,p);}
char* (*a[3]) (char *,char *);
int main(void) {
int i;
char spell1[10] = "accio";
char spell2[10] = "aparecium";
char* result;
a[0] = fun1;
a[1] = fun2;
a[2] = fun3;
result = (*a[?]) (spell1, "c");
printf("%s",result);
result = (*a[?]) (?, "c");
printf("%s",result);
return 0;}
Thank you for your time and help.
Especially, what is char* (*a[3]) (char *, char *) ? I mean we are creating a char pointer array but what is that paranthesis at the end?
It's an array of 3 pointers to function that takes 2 arguments pointer to char and returns a pointer to char.
The assignment a[0] = fun1 doesn't need the arguments, fun is not executed, only assigned to the compatible pointer a[0], you only add the parameters later when you actually want to execute the function, which is done for example in the line result = (*a[?]) (spell1, "c");
char* (*a[3]) (char *,char *);
Starting from a and "going clockwise" or "picking things on the right first":
a
[ is array
3]) of 3
(* pointers
(...) at end, to function
char *,char * taking two parameters of type char*
char* at the start, returning value of type char*
This matches signatures of fun1, fun2 snd fun3. and indeed array is filled with pointers to these 3 functions. Function name without () means pointer to function, it does not call the function, and using & to get address is not needed.
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");
}
In the following code, once I remove the commented part which compares strings, I am getting a seg 11 fault. I am unable to understand why! Rest of the code is working fine. Any help is appreciated!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int compare_scores_desc(const void* scorea, const void* scoreb){
int a = *(int*)scorea;
int b = *(int*)scoreb;
return a-b;
}
int compare_names(const void* namea, const void* nameb){
char** a = *(char**)namea;
char** b = *(char**)nameb;
return strcmp(*a,*b);
}
int main(int argc, char* argv[]){
int scores[7] = {456,234,65,563,67,19,100};
int i;
qsort(scores,7,sizeof(int),compare_scores_desc);
puts("\nThese are the scores in order : \n");
for(i=0;i<7;i++)
printf("%i\n",scores[i]);
char *names[] = {"Krishna","Rama","Bhishma","Arjuna"};
/*qsort(names,4,sizeof(char*),compare_names);*/
puts("------------------");
puts("The names in order are : \n");
for(i=0;i<4;i++)
printf("%s\n",names[i]);
return 0;
}
In compare_names(), you are inappropriately dereferencing the arguments after the cast. The types for the local variables are type char **, but you are casting the arguments as char ** and dereferencing that results in a char *.
namea and nameb are pointers to the elements of your array names[] declared in main(). That means, their types are actually pointer to char *. When you dereferenced these arguments but assigned them to a char **, you cause the local variable to treat the char * as a char ** (your compiler should have issued a diagnostic warning you about this problem). Now, you take a pointer value that is a char *, and dereference it when you pass it to strcmp(). This causes the program to treat sizeof(char *) bytes of the string as a pointer value for the strcmp() function. Since 4 or 8 (or whatever sizeof(char *) is) bytes consisting of printable characters reinterpreted as a pointer value rarely yields a valid pointer, when strcmp() tries to use those pointers, a segmentation fault occurs.
One possible fix is to not dereference when you initialize your local variables. However, the arguments are const void *, so you can avoid the cast altogether if you declare your local variables to be a pointer to a const type:
int compare_names(const void* namea, const void* nameb){
char* const * a = namea;
char* const * b = nameb;
return strcmp(*a,*b);
}
Note that your implementation of compare_scores_desc() fails if a - b results in signed integer overflow. For example, if a is INT_MAX and b is -1. You should fix your implementation to work for all cases.
int compare_scores_desc(const void* scorea, const void* scoreb){
const int *a = scorea;
const int *b = scoreb;
return (*a > *b) - (*a < *b);
}
The problem is in your string comparison function, and here is probably the minimal way to fix it:
int compare_names(const void* namea, const void* nameb){
char* a = *(char**)namea;
char* b = *(char**)nameb;
return strcmp(a,b);
}
The namea and nameb arguments are pointers into the string vector. You understand this, which is why you used the char ** type.
However, all you have to do in the function is retrieve the char * pointers from that array. These char * pointers are already strings. You do not have to dereference them again; just pass them to strcmp.
Your original code has a constraint violation which requires a diagnostic. That should have tipped you off:
/* originally */
char** a = *(char**)namea; /* error: initialization from incompatible type */
You're dereferencing a char **, which produces char *, but you're storing that in a char ** again and dereferencing again, thereby wrongly treating the character data as a pointer.
I was testing an implementation of a comparator function. So here's my code that worked
#include <stdio.h>
#include <string.h>
int compare_names(const void* a, const void* b)
{
char* sa = (char*) a;
char* sb = (char*) b;
return strcmp(sa, sb);
}
int main()
{
char *a = "Bianca";
char *b = "Ana";
printf("Comparing %s with %s returns: %i\n", a, b, compare_names(a, b));
return 0;
}
But I don't think it's right as a and b arguments at compare_names function should turn out to be a pointer to a pointer of char. As pointed in a book I've read, the correct code for the compare_names function would be
int compare_names(const void* a, const void* b)
{
char** sa = (char**) a;
char** sb = (char**) b;
return strcmp(*sa, *sb);
}
But when I ran the code I got a segmentation fault (core dumped).
What am I missing here?
EDIT: I'm using gcc on Linux x64.
#include <stdio.h>
#include <string.h>
int compare_names(const void* a, const void* b)
{
char** sa = (char**) a;
char** sb = (char**) b;
return strcmp(*sa, *sb);
}
int main()
{
char *a = "Bianca";
char *b = "Ana";
printf("Comparing %s with %s returns: %i\n", a, b, compare_names(&a, &b));
return 0;
}
Now it's ok. You have to put the address of a and b in the printf parameters, since there are casted to char**.
char** sa = (char**) a; This line says: "If you direference twice your sa you will end up with a char" The problem is that since your a is a pointer to char you can not direference it twice. So the casting you are doing is generally wrong.
When casting, the compiler trys to interpret your *a which is a char as a pointer to char so when the conversion is performed your *sa ends up being a BadPtr since it fails to convert from char to char *.
So in your strcmp() you have two BadPtr.
You are passing char* arguments, not char** arguments. The example code you posted showing char** does the following:
1. Change generic pointer to a pointer to a string.
2. Compare the strings by dereferencing the char** arguments, meaning you're passing char* arguments to strcmp and return the result.
But you passed char* arguments to your comparison function, so the dereferencing ends up passing arguments of type char to strcmp. Since it expects pointers, the char is interpreted as a memory address. Comparing "hello" to "bye" actually compares the string at address 0x67 to the string at address 0x62, which will segfault.
Pass &a and &b to your comparison function to make it not segfault.
Both versions should work, however, for the second version of the "campare_names" function, you should pass an aditional pointer to each of the char pointers when calling the function.
However your version of the function is correct, it only makes sence to use double pointer parameters, when you are expecting that a function wil alter the pointer position or data being pointed. In this case, since the strcmp function only reads the char* data and doesn't make any changes to it, you don't need an aditional pointer.