I´m starting in C any help will be appreciated.
From a saved string in ´letters´, I want to compare, one by one, if those match the one delivered by the user on argv[]. Moreover, I have a problem on my if clause that I don´t understand.
crypt.c:17:18: error: comparison between pointer and integer ('int' and 'string' (aka 'char *')) [-Werror]
if (g[i] == argv[1])
~~~~ ^ ~~~~~~~
I don´t agree with the compiler this to be a pointer and an integer as I previously defined. g as a string and argv[] as a string. Can someone shed some light in what I am missing, please? I barely know about pointers, can you offer some theory as well? Thanks.
Here's my code:
#include <stdio.h>
#include <cs50.h>
#include <string.h>
int main(int argc, string argv[])
{
if (argc != 2)
{
printf("Wrong Input\n");
}
string g = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
for (int i = 0, n = strlen(g); i < n; i++)
{
if (g[i] == argv[1])
{
printf("True\n");
}
else
printf("False\n");
}
}
I'm going to assume string is typedef char *. (Strings in C are so weird I'd recommend not pretending they're anything but pointers and to not hide that with a string type.)
The trouble is argv is a char **, an array of strings. Whereas g is a char *, or a string. g[0] is the first character of the string, a char. argv[0] is the first string, a char *.
So g[i] == argv[1] is comparing a char with a char *. You probably mean g[i] == argv[1][i].
g is a string, but g[i] is not string anymore. (read: https://www.tutorialcup.com/cplusplus/strings.htm#CharacterArray)
Maybe you can check it as a char.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
// maybe cs50.h have this line inside:
// typedef char* string;
int main(int argc, string argv[])
{
if ((argc != 2) || (strlen(argv[1])!=1))
{
printf("Wrong Input\n");
return 0;
}
// second argument, and first char
char arg = argv[1][0];
string g = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
for (int i = 0, n = strlen(g); i < n; i++)
{
if (g[i] == arg)
{
printf("True\n");
}
else
{
printf("False\n");
}
}
}
Related
This question already has an answer here:
Segmentation fault: boolean expression
(1 answer)
Closed 2 years ago.
I have a question regarding how to use asterisk in my code.
Initially I run !isdigit(argv[1]) [without *] it showed segmentation fault. After referring to an online solution, I realise we should put * in !isdigit(*argv[1]). Can someone explain the function of * in the code?
Below is my code:
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main (int argc, string argv[])
{
if (argc !=2 || !isdigit(argv[1]))
{
printf("Usage: ./caesar key\n");
return 1;
}
int key = atoi(argv[1]);
string p = get_string("plaintext: ");
printf ("ciphertext: ");
for ( int i=0, x=strlen(p); i<x; i++)
{
if (p[i]>='a' && p[i]<='z')
{
p[i] = (p[i] -'a'+key ) %26 +'a';
}
if (p[i]>='A' && p[i]<='Z')
{
p[i] = (p[i] -'A'+key ) %26 +'A';
}
}
printf("%s\n",p);
}
It seems that in this parameter declaration
string argv[]
the name string is an alias for the type char *.
So the parameter declaration may be rewritten like
char * argv[]
that is it is an array of pointers of the type char *. The compiler implicitly adjusts this declaration to char **argv.
So the expression argv[1] gives the second element of the passed to the function main array with the index 1. It has the type char *. The function isdigit expects an object of the type char converted to the type unsigned char. So to get an object of the type char (the first character of the pointed string) you have to dereference the pointer argv[1] having the type char * like *argv[1] or argv[1][0].
It would be more correct to write it at least as
!isdigit( ( unsigned char )*argv[1] )
But in general this check is not enough. You should check that the whole string pointed to by the pointer argv[1] represents a number.
Question: Write a program anagram that sorts the letters in a word, which is useful when searching for anagrams. anagram takes a single argument, which is a string containing only lower-case letters, sorts the letters alphabetically, and then prints the sorted letters. You may use any sorting algorithm you are familiar with, but you must write the sort function yourself. You may not use any sort function provided by a library.
Usage
$ ./anagram hello
ehllo
$ ./anagram positivity
iiiopsttvy
$ ./anagram abcdef
abcdef
The below code is what I have done so far but I get the error
passing char * to parameter of unsigned char converts between pointers to integer types with different sign
#include <stdio.h>
#include <string.h>
void anagram(unsigned char input[])
{
int count[256] = { 0 };
int i;
for (i = 0; input[i] != '\0'; i++)
{
count[input[i]]++;
}
for (i = 0; i < 256; i++)
{
while (count[i] > 0)
{
printf("%c", i);
count[i]--;
}
}
}
int main(int argc, char* argv[])
{
if(argc > 1)
{
anagram(argv[1]);
}
return 0;
}
The short answer to your question is you are getting the pointer sign mismatch warning because you are attempting to pass argv[1] (type char *) to anagram which you have declared with a parameter of unsigned char * (though you use input[], the practical effect is that input decays to a pointer when used as a parameter)
The simple solution while preserving the unsigned char* type for anagram is to cast argv[1] to (unsigned char *) when passed as a parameter to anagram, e.g.
anagram((unsigned char *)argv[1]);
The more practical question is "Do you really need the unsigned char* type to begin with?" While you can escape and pass non-ASCII values as the argument to your program -- is that something you expect and want to protect against by using the unsigned char* (which is 100% fine to do).
Generally, you would simply declare anagram (char *input) (which is your second alternative to eliminate the signed mismatch on the pointers) and limit your loop to looping over the valid range for ASCII characters (see ASCIItable.com)
Either way is fine so long as you handle the pointer signedness consistently. Putting that altogether and removing the magic numbers from your code, you could do something similar to the following:
#include <stdio.h>
#include <string.h>
#define CHRSET 256 /* if you need a constant, define one */
void anagram (unsigned char *input)
{
int i, count[CHRSET] = { 0 };
for (i = 0; input[i] != '\0'; i++)
count[input[i]]++;
for (i = 0; i < CHRSET; i++)
while (count[i] > 0) {
printf("%c", i);
count[i]--;
}
putchar ('\n'); /* provide a POSIX compliant newline before termination */
}
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf (stderr, "error: insufficient input\n"
"usage: %s <string>\n", argv[0]);
return 1;
}
anagram ((unsigned char *)argv[1]);
return 0;
}
(note: you can also move the output of the final newline to main, but unless you plan on smushing multiple sorted strings together by making repeated calls to anagram, then it is better left after the output of each string)
Look things over and let me know if you have further questions.
this is part of a function that takes input from terminal and sorts them depending on what the inputs are (sorting type, a version/variation of the sorting method to use, and the size of the array). This is what I have so far:
int main(int argc, char * argv[]) { //will have 3 arguments not including function name: sortingtype, version and arr size
int * arr = make_arr(argv[2], argv[3]); //[2]
if (strcmp(argv[1], "sortingtype1") == 0) {
SortingType1(arr, argv[3]); //[2][3]
}
else if (strcmp(argv[1], "sortingtype2") == 0) {
SortingType2(arr, argv[3]); //[2][3]
}
else {
return 0;
}
}
void test(){ //[1]
main("sortingtype1", "a", 10); //sortingtype, version and arr size
}
[1] I have a function test() to simulate input from terminal but I don't know if it works that way. I get an error saying that there are too many arguments to main.
[2] Whether or not I remove that testing function, I still get warnings about "passing argument (the arguments with argv[X]) makes integer from pointer without a cast".
[3] These also need to be type int and not type char*, how do I change them?
Any suggestions on how to go about this? I have seen solutions using sscanf, but would prefer a more basic solution around my skill level first for understanding.
Edit: segmentation faults from
int * SortingType2(int * arr, int len) {
for (int i=1; i < len; i++) {
int x = arr[i];
int j = i;
while ((j > 0) && (x < arr[j-1])) {
arr[j] = arr[j-1];
j--;
}
arr[j] = x;
}
return arr;
}
int main(int argc, char * argv[]) {
int size;
if (argc > 3) size = atoi(argv[3]);
int * arr = make_arr(argv[2][0], size);
if (strcmp(argv[1], "sortingtype1") == 0) {
SortingType1(arr, size);
}
else if (strcmp(argv[1], "sortingtype2") == 0) {
SortingType2(arr, size);
}
else {
return 0;
}
}
argv[] is an array of strings, so you need to convert them if you want integers. The simplest way to do this is with atoi() or sscanf(). atoi() is in stdlib.h, and sscanf() is in stdio.h. With atoi(), you just give it a string, and it returns an int. With sscanf(), you provide a string, conversion specifiers, and addresses of variables, just as in the scanf() function, the difference being that here you are scanning a string instead of stdin. Here is an example:
#include <stdio.h> // needed for atoi()
#include <stdlib.h> // needed for sscanf()
int main(int argc, char *argv[])
{
int i = 0;
int j = 0;
/* if argv[1] exists, convert to int */
if (argc > 1)
i = atoi(argv[1]);
/* if argv[2] exists, convert to int */
if (argc > 2)
sscanf(argv[2], "%d", &j);
printf("%d -- %d\n", i, j);
return 0;
}
If you compile this code and execute it you get, for example:
david scratch λ> ./a.out 123 456
123 -- 456
Working with your code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char * argv[])
{
int size;
if (argc < 4) {
printf("Usage: %s sortingType state size\n", argv[0]);
exit(EXIT_FAILURE);
}
size = atoi(argv[3]);
int * arr = make_arr(argv[2], size);
if (strcmp(argv[1], "sortingtype1") == 0) {
SortingType1(arr, size);
}
else if (strcmp(argv[1], "sortingtype2") == 0) {
SortingType2(arr, size);
}
return 0;
}
If you want to call main() from a function, then you have to pass an argument count and a pointer to an array of strings that is null terminated (see What should main() return in C and C++? for the details).
Thus, you might write:
void test(void)
{
char *argv[] = { "sortingtype", "a", "10", 0 };
main(3, argv);
}
It is not common to do this. There is no evidence in your code of the test() function being called.
Note that the arguments are not modifiable strings in the code shown above; normally, the arguments are modifiable. If that's going to matter, you have to work a bit harder:
void test(void)
{
char arg0[] = "sortingtype";
char arg1[] = "a";
char arg2[] = "10";
char *argv[] = { arg0, arg1, arg2, 0 };
main(3, argv);
}
Note too that all the arguments in argv should be strings. Your original code seemed to try to pass 10 rather than "10" but that is not allowed in the argument vector (though 10 could be valid as the argument count, of course).
Please note that calling main() recursively is an eccentric thing to do at best. It is seldom actually necessary, or desirable. It is, however, legal in C — but it is not legal in C++.
C Problem statement: Search an array of integers to find the first first negative integer, if one exists , return its position in the array.
I am aware that I can do this by using indexing, however, I am just wondering why is the program not going into the if condition? Even if I do the casting the code never goes inside if condition.
void find_negative(int argc, char *argv[])
{
int i = 0;
//ignore the first string of arguments because it will be "./problem1.3.c"
for(i =1; i<argc;i++)
{
if(*(argv+i)==2) <-------------------------this is where I get stuck (problem)
{
printf("found it at %d location.\n", i);
}
else
{
printf("All positive.\n");
}
}
}
int main(int argc , char *argv[])
{
find_negative(argc, argv);
return 0;
}
The type of (argv+i) is char**.
The type of *(argv+i) is char*.
In the line,
if(*(argv+i)==2)
you are trying to compare a char* with 2, whose type is int. That explains the compiler error messages.
Perhaps you want to extract an integer from the argument and compare it with 2. Then, you need to use:
if(atoi(*(argv+i))==2)
Some things to note:
*(argv + i) is exactly equivalent to argv[i]. There is no difference whatsoever in this particular code.
argv has type char ** (a pointer to a pointer to char), so *(argv + i) has type char * (a pointer to char). You are comparing this directly to the integer value 2, which is why the compiler is giving you grief, because it is rare to ever compare pointers to integers.
Comparing a string "2" to an integer value 2 won't work, they are different types entirely. If the program is receiving its input via command line arguments, you should parse the input into an actual binary integer.
As an example:
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
for (int i = 1; i < argc; i++)
{
long value = strtol(argv[i], NULL, 10);
if (value < 0)
{
printf("Found a negative integer at position %d\n", i);
return 0;
}
}
// if we get here then there were no negative integers in the input
puts("No negative integers in input");
return 1;
}
The function I used above is documented here.
The input, argv is an array of characters. You probably first need to parse it and convert it to an array of integers.
For exercising my programming skills in C I'm trying to write the strncpy function by myself. Doing that I kept hitting errors, solving most of them eventually I'm stuck with no further inspiration to go on.
The error I receive is:
ex2-1.c:29:3: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
printf("The copied string is: %s.\n", stringb);
The thing is that it's a very common error and that it's also already described on SO, only I can't seem to apply the tips other people have already pointed out. I get that I'm using a wrong type when printing the variable, and when I use the %d format it will return an integer which is probably the ASCII value of the first character, as it doesn't change when increasing the max number of bytes to copy.
Using GDB I've found out that the b variable when done iterating through the while loop holds the correct string, still I can't seem to print it.
I'm probably lacking a very fundamental part of knowledge about the C language and I apologise for asking this novice question (once again). Also I would appreciate it if you could give feedback or point out other flaws in my code.
#include <stdlib.h>
#include <stdio.h>
void strmycpy(char **a, char *b, int maxbytes) {
int i = 0;
char x = 0;
while(i!=maxbytes) {
x = a[0][i];
b[i] = x;
i++;
}
b[i] = 0;
}
int main (int argc, char **argv) {
int maxbytes = atoi(argv[2]);
//char stringa;
char stringb;
if (argc!=3 || maxbytes<1) {
printf("Usage: strmycpy <input string> <numberofbytes>. Maxbytes has to be more than or equal to 1 and keep in mind for the NULL byte (/0).\n");
exit(0);
} else {
strmycpy(&argv[1], &stringb, maxbytes);
printf("The copied string is: %s.\n", stringb);
}
return 0;
}
There is a slight difference between char and char*. The first is a single character whereas the later is a pointer to char (which can point to variable number of char objects).
The %s format specifier really expects a C-style string, which should not only be of type char* but is also expected to be null-terminated (see C string handling). If you want to print a single character, then use %c instead.
As for the program, assuming that what I think you want is what you want, try something like this:
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
static void strmycpy(char *dest, const char *src, size_t n) {
char c;
while (n-- > 0) {
c = *src++;
*dest++ = c;
if (c == '\0') {
while (n-- > 0)
*dest++ = '\0';
break;
}
}
}
int main(int argc, char *argv[]) {
size_t maxbytes;
char *stringb;
if (argc != 3 || !(maxbytes = atoll(argv[2]))) {
fprintf(
stderr,
"Usage: strmycpy <input string> <numberofbytes>.\n"
"Maxbytes has to be more than or equal to 1 and keep "
"in mind for the null byte (\\0).\n"
);
return EXIT_FAILURE;
}
assert(maxbytes > 0);
if (!(stringb = malloc(maxbytes))) {
fprintf(stderr, "Sorry, out of memory\n");
return EXIT_FAILURE;
}
strmycpy(stringb, argv[1], maxbytes);
printf("The copied string is: %.*s\n", (int)maxbytes, stringb);
free(stringb);
return EXIT_SUCCESS;
}
But frankly speaking, this is so fundamental that explaining might just result in writing a book on C. So you will be a lot better off if you just read one already written. For a list of good C books and resources, see The Definitive C Book Guide and List
Hope it helps. Good Luck!