I'm trying to create a C function to return a pointer to the char with the greatest ascii value in a string, but my function is returning 'H' instead of 'o'. I think it's something to do with the if statement in the for loop but I'm not sure what the problem is. Any help is appreciated. Thanks!
char * select_max(char str[]);
int main(void) {
printf("%c\n",select_max("Hello"));
printf("All tests passed successfully.\n");
}
char *select_max(char str[]){
int length = strlen(str);
if(length<1){//returns 0 if string length is less than one
printf("Invalid string.\n");
return 0;
}
char *max = str;
for(int i=0;i<length;i++){
if(str[i] > max){
max = str[i];
}
}
return *max;
}
Try adding a printout so that you can see your bug in action. For example, just before your if:
printf("%c > %c = %d\n", str[i], max, (str[i] > max));
I believe this will quickly reveal the bug. [Hint: there are 5 bugs in your program.]
Compiler is nice enough to give you quite useful warnings, you should follow them, read carefully and try to understand. It won't point out your logical errors but you can deduce these too in this case.
main.c: In function 'main':
main.c:4:5: warning: implicit declaration of function 'printf' [-Wimplicit-function-declaration]
printf("%c\n",select_max("Hello"));
^~~~~~
main.c:4:5: warning: incompatible implicit declaration of built-in function 'printf'
main.c:4:5: note: include '<stdio.h>' or provide a declaration of 'printf'
main.c: In function 'select_max':
main.c:10:18: warning: implicit declaration of function 'strlen' [-Wimplicit-function-declaration]
int length = strlen(str);
^~~~~~
main.c:10:18: warning: incompatible implicit declaration of built-in function 'strlen'
main.c:10:18: note: include '<string.h>' or provide a declaration of 'strlen'
You first need to include the libraries that you use functions from, printf is from stdio.h and strlen is from string.h.
main.c:22:12: warning: returning 'char' from a function with return type 'char *' makes pointer from integer without a cast [-Wint-conversion]
return *max;
^~~~
You appear to be confusing chars with char*s. Since select_max is logically supposed to return just a character, (and you are already returning a char) declaring it as below will suffice.
#include<stdio.h>
#include<string.h>
char select_max( char str[] );
main.c:19:17: warning: assignment to 'char *' from 'char' makes pointer from integer without a cast [-Wint-conversion]
max = str[i];
And in the implementation of select_max, there is a similar problem. The temporary variable to hold the highest character is of type char* where it just needs to be a char:
char select_max(char str[]){
// ^___
int length = strlen(str);
if(length<1){//returns 0 if string length is less than one
printf("Invalid string.\n");
return 0;
}
// Initialize it to 0, has to be lower than any ASCII letters in order your algorithm to work. DO NOT leave it uninitialized.
char max = 0; // <---
for(int i=0;i<length;i++){
if(str[i] > max){
max = str[i];
}
}
return max;
}
The code above defines max as a char and initializes it to 0. Assigning str to it was pointless anyway. You are iterating through your string one character at a time and storing the character in a temporary container.
Note that the code in the for loop had already written as if it was of type char.
The same algorithm of course can be implemented in various ways but I suppose this was what you were trying to do.
Related
what I have is a string that I get from txt file.
fgets(num_string, lenght, file);
num_string = "011110110101"
So than I select the first number and display it:
printf("Number: %c", num_string[0]);
After that my program gets all the numbers in string with this loop and it should then check each number if its 0 or 1:
for(j=0; j<=11; j++){
printf("numbers: %c\n", num_string[j]);
if(strcmp(num_string[j], zero)==0){
num_of_zeros++;
printf("\nNum of zeros: %d", num_of_zeros);
}
else{
num_of_ones++;
printf("\nNum of ones: %d", num_of_ones);
}
}
But the if statement does not want to work. Here is the problem that it writes in terminal:
AOC_2021_day_3.c: In function 'main':
AOC_2021_day_3.c:27:27: warning: passing argument 1 of 'strcmp' makes pointer from integer without a cast [-Wint-conversion]
if(strcmp(num_string[j], zero)==0){
^~~~~~~~~~
In file included from AOC_2021_day_3.c:3:0:
c:\mingw\include\string.h:77:38: note: expected 'const char *' but argument is of type 'char'
_CRTIMP __cdecl __MINGW_NOTHROW int strcmp (const char *, const char *) __MINGW_ATTRIB_PURE;
^~~~~~
I would appreciate any help :D
strcmp is for comparing to cstrings. In this case, you do not need strcmp at all. You want to check whether a specific character inside num_string is 0 or not. The if(strcmp(num_string[j], zero)==0) statement can be replaced with if(num_string[j] == '0').
I want to print the days of the week in this program but it doesn't work, what can I do to fix it ?
#include<stdio.h>
struct month{
int date[12];
char day[7];
}mon;
main()
{ int i;
strcpy(mon.day[0],"Sunday");
strcpy(mon.day[1],"Monday");
strcpy(mon.day[2],"Tuesday");
strcpy(mon.day[3],"Wednesday");
strcpy(mon.day[4],"Thursday");
strcpy(mon.day[5],"Friday");
strcpy(mon.day[6],"Saturday");
for(i=0;i<7;i++)
{
printf("Day %d is %c\n",i+1,mon.day[i]);
}
}
You are trying to store strings in char. However, a string is an array of char. Instead of this:
char day[7];
You need something such as:
char day[7][16];
Now you have 16 char to fit in a weekday, and you have that seven times, one for each day. Also, your print is wrong. To print strings, you need %s, not %c. %c is just for one single char:
printf("Day %d is %s\n", i + 1, mon.day[i]);
Another way of doing it is to have an array of char* instead of char and only storing the address of the strings rather than copying the strings:
char *day[7];
Then store the addresses like this:
mon.day[0] = "Sunday";
mon.day[1] = "Monday";
mon.day[2] = "Tuesday";
...
And print it the same way, with %s.
If you try to compile your program, your compiler will give you certain warnings. Like
Problem 1:
source_file.c:10:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
main()
^
The proper signature of main() is int main(void), for usual hosted environments.
Problem 2:
source_file.c: In function ‘main’:
source_file.c:13:5: warning: implicit declaration of function ‘strcpy’ [-Wimplicit-function-declaration]
strcpy(mon.day[0],"Sunday");
^
source_file.c:13:5: warning: incompatible implicit declaration of built-in function ‘strcpy’
source_file.c:13:5: note: include ‘<string.h>’ or provide a declaration of ‘strcpy’
You'd need to include string.h header file which contains the declaration for strcpy().
Problem 3:
source_file.c:13:12: warning: passing argument 1 of ‘strcpy’ makes pointer from integer without a cast [-Wint-conversion]
strcpy(mon.day[0],"Sunday");
This indicates, the first argument of strcpy() expects a char *, but you're passing a char, casted to an int.
This is the most important point here, as you'd see, you need to pass a buffer which can contain the content from the copied string. Thu's, you'd need
day to be a 2-D array
use day[i] to store the content
use %s to print the content thereof.
For constants like day and month, better constructed like the following, unless you are practicing with struct.
#include<stdio.h>
int main()
{
const char *day[] = {"Sunday", "Monday", "Tuesday","Wednesday", "Thursday", "Friday", "Saturday" };
//^^^^^ array of strings.
for(int i=0;i<7;i++)
printf("Day %d is %s\n",i+1,day[i]);
return 0;
}
#include <stdio.h>
#include <string.h>
int myprint(char_array){
char mystring[80];
strcat(mystring, "\n");
printf("%s", mystring);
return 0;
}
int main(int argc, char** argv){
int count = 5;
char letter = 'c';
printf("decimal: %d, char: %c\n", count, letter);
myprint("sup");
return 0;
}
I get warnings on compile:
cchilders:~/projects/buildyourownlisp_in_C/ch3 [master]$ compile basics.c basics
basics.c: In function ‘myprint’:
basics.c:4:5: warning: type of ‘char_array’ defaults to ‘int’
int myprint(char_array){
^
It compiles, but my myprint function doesn't work:
cchilders:~/projects/buildyourownlisp_in_C/ch3 [master]$ ./basics
decimal: 5, char: c
I see this answer warning: return type defaults to ‘int’ [-Wreturn-type] but doesn't apply to me since I did declare int main(...)
I also see this declaration of functions:
return_type function_name( parameter list ) {
body of the function
}
And for myprint I declare as taking int and return 0. What does this warning mean and why doesn't my function work? Thank you
ANSWER:
void myprint(char mystring[]){
strcat(mystring, "\n");
printf("%s", mystring);
}
quiets the warnings, but causes Segmentation fault (core dumped)
Changing to
void myprint(char[] mystring){
strcat(mystring, "\n");
printf("%s", mystring);
}
makes it worse:
cchilders:~/projects/buildyourownlisp_in_C/ch3 [master]$ cc -std=c99 -Wall basics.c -o basics
basics.c:4:21: error: expected ‘;’, ‘,’ or ‘)’ before ‘mystring’
void myprint(char[] mystring;){
^
basics.c: In function ‘main’:
basics.c:15:5: warning: implicit declaration of function ‘myprint’ [-Wimplicit-function-declaration]
myprint("sup");
^
I also tried
void myprint(char[] mystring;){...
and
void myprint(char[] mystring,){...
As others have pointed out, you didn't specify a type for char_array, so it is assumed to be int. Changing it to char char_array[] fixes this.
Your other problem is that you're passing a string constant ("sup") to this function and are then attempting to modify it. String constants are stored in a read-only section of memory, so you can't modify it.
Given that you're only printing the string with a newline, you can do this instead:
void myprint(char mystring[]){
printf("%s\n", mystring);
}
You are not providing a data type for char_array in
int myprint(char_array)
You need char * or whatever you want it to be.
Firstly, function definitions should be like
return-type function-name ( parameter-type parameter-name, parameter-type parameter-name)
{ ... }
You did not specify either a parameter type or a parameter name. If you mean char_array to mean a type, you need to define it first, using a typedef or a struct or something else. If you mean char_array to be a parameter name, you need to specify its type, as
char[] char_array
say. Also, in this case, you do not actually use the variable char array anywhere in the function myprint. So the argument "sup" is not being used at all.
After edit to the question:
Try
char str[] = "sup";
myprint(str);
instead. As far as I know, you can't pass a string (a character array) by value.
int myprint(char_array)
What type has the parameter with name char_array? Because you didn't specify it, the compiler assumed it to be an int. Luckily it's warning you about that.
Don't rely on such behaviour, though. (I don't know whether this is still legal in C11 for example) Just write correct function declarations, including parameter types.
You need to specify the type of the parameters you expect to be passed to the function. There are mistakes in the function too. char_array is of char* type. You need to copy every part of the passed array to your local array, THEN only can you call printf for this function to work
After reading Structure and Interpretation of Computer Programs (SICP) I decided to find a way to implement some of these functional programming techniques using C. I tried to write a program that makes a pair whose first argument is a name of the function and second arg is any function that takes one arg and returns one arg. Using implementation below I was expecting to see
an output like:
fact(7) = 5040
fib(7) = 13
but instead I am getting
fact(7) = 5040
fib(7) = 0
along with warnings
$ cc map.c
map.c: In function ‘main’:
map.c:41:17: warning: assignment from incompatible pointer type [enabled by default]
maps[0].f_ptr = &fact;
^
map.c:43:17: warning: assignment from incompatible pointer type [enabled by default]
maps[1].f_ptr = &fib;
^
map.c:47:7: warning: passing argument 1 of ‘maps[i].f_ptr’ makes pointer from integer without a cast [enabled by default]
ans = (int) maps[i].f_ptr((int) num);
^
map.c:47:7: note: expected ‘void *’ but argument is of type ‘int’
map.c:47:13: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
ans = (int) maps[i].f_ptr((int) num);
^
map.c:52:7: warning: passing argument 1 of ‘maps[i].f_ptr’ makes pointer from integer without a cast [enabled by default]
ans2 = (int) maps[i].f_ptr((int) num);
^
map.c:52:7: note: expected ‘void *’ but argument is of type ‘int’
map.c:52:14: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
ans2 = (int) maps[i].f_ptr((int) num);
during compilation. Looking at the code I don't see the problem but then again I haven't used C in quite some time. Is there a better way to implement such a construct and why is fib(7) printing a 0 instead of 13?
Here's my code:
struct Map
{
char* name;
void* (*f_ptr)(void*);
};
int fact(int a) {
if (a == 0)
return 0;
if (a == 1)
return 1;
return a * fact (a-1);
}
int fib(int a) {
if (a == 0)
return 0;
if (a == 1)
return 1;
return fib(a-1) + fib(a-2);
}
int findFunc (char* str, struct Map map)
{
if (map.name == str)
return 1;
return 0;
}
int main()
{
int i = 0;
int ans = 0;
int ans2 = 0;
int num = 7;
struct Map maps[2];
maps[0].name = "fact";
maps[0].f_ptr = &fact;
maps[1].name = "fib";
maps[1].f_ptr = &fib;
for (i; i < (sizeof(maps)/sizeof(maps[0])); i++) {
if (findFunc("fact", maps[i]))
ans = (int) maps[i].f_ptr((int) num);
}
for (i; i < (sizeof(maps)/sizeof(maps[0])); i++) {
if (findFunc("fib", maps[i]))
ans2 = (int) maps[i].f_ptr((int) num);
}
printf("fact(%d) = %d\n", num, ans);
printf("fib(%d) = %d", num, ans2);
return 0;
}
String comparisons
This is not how you do string comparison in C.
if (map.name == str)
This is how you do string comparison in C.
if (0 == strcmp(map.name, str))
Because strings in C are just pointers to characters, map.name == str checks if map.name and str are identical pointers (point to the same block of memory), not whether what they point to is the same.
for loops
Your code is probably reporting fib(7) = 0 because it's failing to find fib. One possible culprit is the string comparison issue I mentioned. However, your for loop syntax is also odd:
for (i; i < (sizeof(maps)/sizeof(maps[0])); i++) {
You don't set i to anything, so this means, "Starting from wherever i happens to be, do the following..."
To loop over all of maps, use this:
for (i = 0; i < (sizeof(maps)/sizeof(maps[0])); i++) {
type warnings
As #alk said in a comment, the reason you're getting all of those warnings is because you've declared a function type of void* (*f_ptr)(void*);, even though your functions are int (*)(int). If you want to keep using void* to allow different types, and you're careful enough with your types to make this work, then you can add casts to silence the warnings.
maps[0].f_ptr = (void *(*)(void*)) &fact;
ans2 = (int) maps[i].f_ptr((void*) num);
Etc.
Better implementations?
A "real" implementation of mapping functions to names would use a hash table, instead of linearly searching for matching names. Implementing a hash table in C would add complexity and may not be worth it for this exercise.
but instead I am getting
[...]
fib(7) = 0
The code misses to initialise i to 0 for the 2nd for-loop.
I'm new to C and I try to make a program counting words in a sentence given as arguments when running the program. A word is a character or several seperated by either: ' ', '\n', ',' or '.'. Example: ./words abc abc = 2 words
But I keep getting: "segementation fault(core dumped)". Following is code:
int main(char **argv)
{
char buf[80];
sprintf(buf,"%d words\n",words(argv));
write(1,buf,strlen(buf));
return 0;
}
int words(char **argv)
{
int i=0, sum=0;
while(argv[i] != '\0')
{
if(argv[i] == '.' || argv[i] == ',' || argv[i] == ' ' || argv[i] == '\n')
sum++;
i++;
}
}
Argv is a **char or a pointer to an array of strings. Your code is treating it as if it is a single string so is looping through the pointers to strings and counting them. As none of these pointers is null the program continues beyond the end of the array causing a segfault.
me.c:2:5: warning: first argument of âmainâ should be âintâ [-Wmain]
me.c:2:5: warning: âmainâ takes only zero or two arguments [-Wmain]
me.c: In function âmainâ:
me.c:4:1: warning: implicit declaration of function âwordsâ [-Wimplicit-function-declaration]
me.c:5:1: warning: implicit declaration of function âwriteâ [-Wimplicit-function-declaration]
me.c:5:1: warning: implicit declaration of function âstrlenâ [-Wimplicit-function-declaration]
me.c:5:13: warning: incompatible implicit declaration of built-in function âstrlenâ [enabled by default]
me.c: In function âwordsâ:
me.c:11:16: warning: comparison between pointer and integer [enabled by default]
me.c:11:33: warning: comparison between pointer and integer [enabled by default]
me.c:11:51: warning: comparison between pointer and integer [enabled by default]
me.c:11:69: warning: comparison between pointer and integer [enabled by default]
gcc -Wall filename.c will produces all of the above warnings
These are the warnings in your code. Avoid all. and then try.
Please found Answers for these By searching on google
how to use command line arguments
how to declare a function
how to compare strings and how '.' is differ from "."
If I am not mistaken, then the arguments are automatically split into separate character strings. This is why you get a pointer to a pointer (e.g char ** instead of char*). You are dereferencing the argv array only once. Try this:
while(argv[i] != NULL) {
i++;
}
Second, you wont be able to detect newlines that way, since by definition you cannot pass newline in the arguments. What you probably want to do is parse the input from stdin and invoke your program like this:
echo "abc abc" | ./words
or
./words < SOME_TEXT_FILE
Last but not least your words function does not return anything, it needs to return i:
int words(char** argv) {
//...
return i;
}
That is probably the reason why your program segfaults, since the return value of words() will be NULL and then sprintf will try to dereference the result of the function.
So the whole function needs to look somewhat like this:
int words(char** argv) {
int counter = 0;
while(char[i] != NULL) {
int j = 0;
while(char[i][j] != '\0') {
if(char[i][j] == '.') { //no need to check for '\n'...
counter++;
}
j++;
}
i++;
counter++;
}
return counter;
}
1. Iterate over argv.(having in mind that argv[i] is a pointer to char, argv[0] holds name of the program being executed, and last element of argv is NULL pointer.
2. use strtok function from string.h library to split argv[i] with " .,\n". (every time strtok returns non-NULL value you increment words count).
With some reading on command line arguments and strtok you can easily make it work with any arguments passed.