Comparing every char in a string to a constant - c

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);
}
}
}

Related

How store address of an array[] in a variable

This seems like a silly question. I have an array of chars and want to store the address of the array in another variable, but can't seem to declare the correct type for the array address (I'm using gcc):
IN:
int main(void){
char cha[] = "abcde";
char **arrayAddress = &cha;
}
OUT:
arrayaddress.c: In function ‘main’:
arrayaddress.c:3:25: warning: initialization of ‘char **’ from incompatible pointer type ‘char (*)[6]’ [-Wincompatible-pointer-types]
3 | char **arrayAddress = &cha;
| ^
This is expected, I have read elsewhere that the type of cha should be char(*)[6]. But when I try to declare arrayAddress with this type, my program fails:
IN:
int main(void){
char cha[] = "abcde";
char (*)[6]arrayAddress = &cha;
}
OUT:
arrayaddress.c: In function ‘main’:
arrayaddress.c:3:10: error: expected identifier or ‘(’ before ‘)’ token
3 | char (*)[6]arrayAddress = &cha;
| ^
make: *** [<builtin>: arrayaddress] Error 1
^
How do I define arrayAddress correctly?
It is written:
char (*arrayAddress)[6] = &cha;
Notice that the name of variable gets tucked in middle of the expression.
Arrays decay to pointers.
char cha[] = "abcde";
char *p1 = cha;
char (*arrayptr)[sizeof(cha)] = &cha;
cha, &cha[0] and &cha reference the same first element of the array cha, the only difference is the type.
cha and &cha[0] has type: pointer to char
&cha has type: pointer to array of 6 char elements.
If your compiler supports typeof extension (gcc does) then you can define the pointer as:
typeof(char (*)[6]) arrayAddress = &cha;
Or even cleaner as:
typeof(char[6]) * arrayAddress = &cha;

Why does this swapping of strings through pointers work in C?

So far as I know, when we create an array or string, their names are pointers to their first elements. And the pointer, in this case, cannot be changed.
However, this piece of code works:
#include <stdio.h>
void swapString(char **str1_ptr, char **str2_ptr)
{
char *temp = *str1_ptr;
*str1_ptr = *str2_ptr;
*str2_ptr = temp;
}
int main()
{
char strings[][30] = {"Test1","Test2","Test3"};
int i;
swapString((char **)&strings[0],(char **)&strings[1]);
for(i=0;i<3;i++){
printf("%s\n",strings[i]);
}
return 0;
}
Why does this work well?
Is it a good practice to swap strings (or arrays in general) in this way?
When it is not a good idea to use this approach?
Why does this work well?
It does not work well.
It seems to work well because you lie to your compiler and use insufficient test data.
void swapString(char **str1_ptr, char **str2_ptr)
{
char *temp = *str1_ptr;
*str1_ptr = *str2_ptr;
*str2_ptr = temp;
}
You claim to provide a pointer to a pointer. As a consequence this functions swaps as much bytes between two places as a pointer takes. That is 4 or 8 bytes on most systems.
But then you pass addresses of arrays, not pointers to pointers:
char strings[][30] = {"Test1","Test2","Test3"};
swapString((char **)&strings[0],(char **)&strings[1]);
This is causing undefined behaviour. You are using casts because your compiler told you that this is crab if you remove them:
test.c:15:28: warning: passing argument 2 of ‘swapString’ from incompatible pointer type [-Wincompatible-pointer-types]
15 | swapString(&strings[0],&strings[1]);
| ^~~~~~~~~~~
| |
| char (*)[30]
test.c:3:41: note: expected ‘char **’ but argument is of type ‘char (*)[30]’
As a result the function thinks it swaps a pointer but instead it swaps the first 8 bytes of your array.
To verify this you could use longer strings:
#include <stdio.h>
void swapString(char **str1_ptr, char **str2_ptr)
{
char *temp = *str1_ptr;
*str1_ptr = *str2_ptr;
*str2_ptr = temp;
}
int main()
{
char strings[][30] = {"Test111111","Test222222","Test333333"};
int i;
swapString((char **)&strings[0],(char **)&strings[1]);
for(i=0;i<3;i++){
printf("%s\n",strings[i]);
}
return 0;
}
And then you get the result you deserve. ;)
Test$ ./test
Test222211
Test111122
Test333333
In case of 32bit addresses you need to make the first 4 bytes of your strings distinguishable.
As you can see, there are no swapped pointers at all. Just the start of your arrays is messed up.
If you want to swap strings by just swapping pointers, you need to change your array definition:
char *strings[] = {"Test111111","Test222222","Test333333"};
swapString(&strings[0],&strings[1]);
As a side effect you can also drop the casts from your function call as the types now match what is expected.

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");
}

passing argument makes pointer from integer without a cast

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");
}

C arrays of arrays: why do I need to cast TO const here?

Why do I need to change the print_args call in this code to print_args(argc, (const char**)argv) to make it compile?
#include <stdio.h>
void print_args(int argc, const char *argv[]) {
for (int i = 0; i < argc; ++ i) {
puts(argv[i]);
}
}
int main(int argc, char *argv[]) {
print_args(argc, argv);
return 0;
}
When I compile it with gcc I get this error:
$ gcc -Werror -std=c99 -g const.c -o const
const.c: In function ‘main’:
const.c:10:2: error: passing argument 2 of ‘print_args’ from incompatible pointer type [-Werror]
const.c:3:6: note: expected ‘const char **’ but argument is of type ‘char **’
cc1: all warnings being treated as errors
(Note that this is just a simplified example code to illustrate the problem.)
The comp.lang.c FAQ has a question on this, summarizing:
The reason that you cannot assign a char ** value to a const char **
pointer is somewhat obscure. Given that the const qualifier exists at
all, the compiler would like to help you keep your promises not to
modify const values. That's why you can assign a char * to a const
char *, but not the other way around: it's clearly safe to "add"
const-ness to a simple pointer, but it would be dangerous to take it
away...In C, if you must assign or pass pointers which have qualifier
mismatches at other than the first level of indirection, you must use
explicit casts
Here's the example it gives, where line 3 should give a warning:
const char c = 'x'; /* 1 */
char *p1; /* 2 */
const char **p2 = &p1; /* 3 */
*p2 = &c; /* 4 */
*p1 = 'X'; /* 5 */
Lines 1 and 2 are obviously fine. On line 4, &c has type pointer to const char, and since char ** is type pointer to pointer to const char, then *p2 is also of type pointer to const char, so the statement is fine. Line 5 is also fine, because p1 is type pointer to char, so you can modify what it points to.
So if line 3 is OK, then you end up doing exactly what you expect const to prevent you from doing, modifying the char pointed to by a pointer to pointer to const char, so line 3 is not allowed, and you can't assign char ** to a const char ** without a cast.
Note that putting the cast in merely hides the problem, it doesn't fix it. Line 3 above would work if you added the cast, and you'd be able to indirectly modify an apparently const char. While it's not always true, this is a good example of where succumbing to an apparent need to cast in C is often just a mistake.
Note that in C++, you could declare your function parameter const char * const * argv and it would work without a cast, and prevent the indirect modification.

Resources