I got a problem with variable number of arguments. I'm pretty bad in C. In my task i need to specify the types in undeclared parameters. It seems i don't have a reason to do it, because i'm using just a string, but i need to use it with <stdarg.h>. The function suppose to print words which have the specific letter repeating 3+ times. So, when I'm trying this code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
void repeatingLetter(char* sentence, char letter)
{
char* word = strtok(sentence, " ");
while (word != NULL) {
int count = 0;
int len = strlen(word);
for (int i = 0; i < len; i++) {
if (word[i] == letter) {
count++;
}
}
if (count >= 3) {
printf("%s\n", word);
}
word = strtok(NULL, " ");
}
}
void findWords(int numSentences, ...)
{
va_list args;
va_start(args, numSentences);
char letter;
printf("Enter a letter to check: ");
scanf("%c", &letter);
for (int i = 0; i < numSentences; i++)
{
char* sentence = va_arg(args, char*);
printf("Words in '%s' with '%c' repeated 3 or more times:\n", sentence, letter);
repeatingLetter(sentence, letter);
printf("\n");
}
va_end(args);
}
int main()
{
int numSentences;
printf("Enter a number of sentences: ");
scanf("%d", &numSentences);
getchar();
char** sentences = (char**)malloc(numSentences * sizeof(char*));
for (int i = 0; i < numSentences; i++)
{
sentences[i] = (char*)malloc(100 * sizeof(char));
printf("Enter a sentences %d: ", i + 1);
fgets(sentences[i], 100, stdin);
sentences[i][strcspn(sentences[i], "\n")] = '\0';
}
findWords(numSentences, sentences);
for (int i = 0; i < numSentences; i++)
{
free(sentences[i]);
}
free(sentences);
return 0;
}
I'm getting something like that:
Enter a number of sentences: 3
Enter a sentences 1: Hello world
Enter a sentences 2: oooooops
Enter a sentences 3: gdsgdgdg
Enter a letter to check: o
Words in '╨Ъ.┌c' with 'o' repeated 3 or more times:
Words in '╨Ъ.┌c' with 'o' repeated 3 or more times:
Words in 'o
gdgdg
d
' with 'o' repeated 3 or more times:
I don't understand what's a problem. Can you please help me?
I have tried to do this with integer and float. There weren't any problems, but I can't understand what's wrong with strings
In my task i need to specify the types in undeclared parameters. It seems i don't have a reason to do it, because i'm using just a string, but i need to use it with <stdarg.h>. The function suppose to print words which have the specific letter repeating 3+ times
These parameters are not "undeclared" . ...
is the declaration, a placeholder for a variable number of arguments. This is what stdargs
is all about.
And there is a function that will get these parameters, all strings as you said, and print all that have some letter occurring at least n
times.
The probable target of your program is to call the function from a variadic function with a variable number of arguments. If it is not you objective please post the task requirements.
Complete code is at the end for this example
void repeatingLetter(char* sentence, char letter)
{
char* word = strtok(sentence, " ");
while (word != NULL)
{
int count = 0;
int len = strlen(word);
for (int i = 0; i < len; i++)
{
if (word[i] == letter) { count++; }
}
if (count >= 3) { printf("%s\n", word); }
word = strtok(NULL, " ");
}
}
About the original code
printf()
things inside the target function.void
In C
0
is false
. Only 0
. Return false
for a string not matching the criteria. Just that. If you have a sentence, break that into words and then call the function with the words...
int repeatingLetter(
const char* word, const char letter, size_t times)
{
if (word == NULL) return 0;
if ((letter == 0) && (times == 0)) return 0;
char* pl = (char*)word; // pointer to 1st letter
size_t count = 0;
while (*pl != 0)
{
if (*pl == letter)
if (++count == times) return 1;
++pl;
}
return 0;
}
This one does just that, but no more than that. Returns 1
if letter
appears at least times
times in the word
.
To test it you can just write another function in advance, like this
int t_repeat(const char* s, const char letter, size_t times)
{
printf("\n\
sentence: \"%s\"\n\
letter: '%c'\n\
total number of times: %llu\n",
s, letter, times);
int res = repeatingLetter(s, letter, times);
printf("\n\tfunction returned %d\n", res);
return 0;
}
it is trivial, but can save some time if you do this before. See this code for main()
:
int main(void)
{
t_repeat("aaa", 'a', 3);
t_repeat("aa", 'a', 3);
t_repeat("aaa", 'a', 4);
t_repeat("aaa", 0, 4);
t_repeat("aaa", 'a', 0);
t_repeat(NULL, 'a', 0);
return 0;
}
So it is easy to type some conditions and test it, before even considering the rest of the program.
ouptut for this test
sentence: "aaa"
letter: 'a'
total number of times: 3
function returned 1
sentence: "aa"
letter: 'a'
total number of times: 3
function returned 0
sentence: "aaa"
letter: 'a'
total number of times: 4
function returned 0
sentence: "aaa"
letter: ''
total number of times: 4
function returned 0
sentence: "aaa"
letter: 'a'
total number of times: 0
function returned 0
sentence: "(null)"
letter: 'a'
total number of times: 0
function returned 0
So it seems to be ok to go on
If findWords
is
void findWords(
const char letter,
const size_t n_times,
const size_t N, ...)
then main()
for a test could be as simple as
int main(void)
{
findWords('x', 3, 8,
"xvalue",
"xvaluexx",
"xxxAll",
"Sxtxaxck",
"Sxtxaxck",
"Stack Overflow",
"xOverflowx",
"xOverflowxx"
);
return 0;
}; // main()
output of such test
"xvaluexx"
"xxxAll"
"Sxtxaxck"
"Sxtxaxck"
"xOverflowxx"
Here is a simple implementation for findWords
:
// find 'l' at least 't' times in each of the
// 'N' arguments in '...'
void findWords(
const char l, const size_t t, const size_t N, ...)
{
va_list args;
va_start(args, N);
for (size_t i = 0; i < N; i++)
{
char* string = va_arg(args, char*);
if (repeatingLetter(string, l, t) != 0)
printf("\"%s\"\n",string);
}
va_end(args);
}
And is almost the same function as t_repeat()
in the first test.
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int repeatingLetter(const char*, const char, size_t);
void findWords(const char, const size_t, const size_t, ...);
int main(void)
{
findWords('x', 3, 8,
"xvalue",
"xvaluexx",
"xxxAll",
"Sxtxaxck",
"Sxtxaxck",
"Stack Overflow",
"xOverflowx",
"xOverflowxx"
);
return 0;
}; // main()
int repeatingLetter(
const char* word, const char letter, size_t times)
{
if (word == NULL) return 0;
if ((letter == 0) && (times == 0)) return 0;
char* pl = (char*)word; // pointer to 1st letter
size_t count = 0;
while (*pl != 0)
{
if (*pl == letter)
if (++count == times) return 1;
++pl;
}
return 0;
}
// find 'l' at least 't' times in each of the
// 'N' arguments in '...'
void findWords(
const char l, const size_t t, const size_t N, ...)
{
va_list args;
va_start(args, N);
for (size_t i = 0; i < N; i++)
{
char* string = va_arg(args, char*);
if (repeatingLetter(string, l, t) != 0)
printf("\"%s\"\n",string);
}
va_end(args);
}
va_list
When you declare a function like
void findWords(
const char l, const size_t t, const size_t N, ...)
the compiler gets aware of the variadic nature of the function. Then, when a call is made like in
int main(void)
{
findWords('x', 3, 8,
"xvalue",
"xvaluexx",
"xxxAll",
"Sxtxaxck",
"Sxtxaxck",
"Stack Overflow",
"xOverflowx",
"xOverflowxx"
);
return 0;
}; // main()
code is inserted to build the va_list
for this call and pass it down to findWords
. Here the number of arguments is a fixed number. main
is not a variadic function. findWords()
is variadic, and the va_list
it gets can be even forwarded to inner functions.
If you need to build such a thing at runtime you can use a custom struct
, or a simple NULL
-terminated void*
array. But you will not use stdargs.h
. If you do that you can even mix the argument types or pass down a list of type/value pairs.
main(int argc,char* argv[]
gets a variable number of argumentsIn fact once the program is loaded the number of arguments is fixed: the OS builds the argv
array and sets up argc
.