I need it to only print the first capital of each word The point of this is to make acronyms from sentences by calling the function above.
EX.
input: Hello output: H.
input: MACinery Bean output: M.C.B.
Desired output: M.B.
void CreateAcronym(char userPhrase[50], char userAcronym[50]){
int len, up, uptwo;
char upper[50];
int isupper();
len = strlen(userPhrase);
for (int i = 0; i < len; i++){
up = isupper(userPhrase[i]);
uptwo = isupper(userPhrase[i+1]);
if (up != 0 && uptwo == 0){
strcpy(&upper[i], &userPhrase[i]);
printf("%c.", upper[i]);
}
}
printf("\n");
The first letter of each word is either the beginning of the string or the previous character being a space. So you must test for that in your condition, not compare the current character and the next character.
for (int i = 0; i < len; i++){
if ((i == 0 || userPhrase[i-1] == ' ') && isupper(userPhrase[i]) {
printf("%c.", userPhrase[i]);
}
}
int isupper();
This is a strange prototype for the <ctype.h> function isupper. I'm not really sure if it's well defined. There are two ways I know to get a correct prototype for this function:
#include <ctype.h>, typically somewhere near the top of your file. This is the way we most often see.
int isupper(int); will also introduce the correct prototype.
Nonetheless I have no doubt the default argument promotions that occur are causing the correct type to be passed, so even if the behaviour is undefined it's probably no trouble.
We need to talk some more about that int argument, though, hence bringing it to your attention. We're expected to ensure that int argument is either an unsigned char value or EOF, but the value you passed is instead a char value that may be neither. When passing char values to <ctype.h> functions, we should (generally, but not always) cast the argument to unsigned char like so:
up = isupper((unsigned char) userPhrase[i]);
As far as the rest of your code goes, I think perhaps you may need to think more about what your algorithm is meant to do. I'ma use a functional style, because I think it makes sense for the sake of explanation here. You should translate this to a procedural style for class. So for my example (which may not even compile 🤷♂️ but is there to help you think about your algorithm) you can expect my continuations to be facilitated by something like:
typedef int fun(), contin(char *, char const *, fun **);
It seems to me like you want to skip leading non-alphabet characters, extract the first alpha, then skip any alpha until you reach non-alpha again. For example, the first step:
int skip_nonalpha(char *dst, char const *src, fun **f) {
if (!*src) return *dst = 0;
if (!isalpha((unsigned char) *src)) return skip_nonalpha(dst, src + 1, f);
return ((contin *) *f)(dst, src, f + 1);
}
In the function above you can see the argument passed to isalpha is explicitly converted to unsigned char, as I mentioned earlier. Anyhow, the next step is to extract and convert to upper:
int extract_toupper(char *dst, char const *src, fun **f) {
*dst = toupper(*src);
return ((contin *) *f)(dst + 1, src + 1, f + 1);
}
We don't need the explicit conversion in the function above because we already know src is alpha, which makes it a positive value (within the range of [0..UCHAR_MAX]). Next, skip the rest of the alpha characters:
int skip_alpha(char *dst, char const *src, fun **f) {
if (!*src) return *dst = 0;
if (isalpha((unsigned char) *src)) return skip_alpha(dst, src + 1, f);
return ((contin *) *f)(dst, src, f + 1);
}
Finally, wrapping it all up:
int make_acronym_tail(char *dst, char const *src, fun **f) {
return skip_nonalpha(dst, src,
(fun *[]){ (fun *) extract_alpha
, (fun *) skip_alpha
, (fun *) make_acronym_tail)
});
}
int make_acronym(char *dst, char const *src) { return make_acronym_tail(dst, src, NULL); }
Now assuming this compiles you should be able to use it like:
char phrase[] = "hello world", acronym[strlen(phrase) + 1];
make_acronym(acronym, phrase);
Related
Take the following function:
char * slice(const char * str, unsigned int start, unsigned int end) {
int string_len = strlen(str);
int slice_len = (end - start < string_len) ? end - start : string_len;
char * sliced_str = (char *) malloc (slice_len + 1);
sliced_str[slice_len] = '\0';
// Make sure we have a string of length > 0, and it's within the string range
if (slice_len == 0 || start >= string_len || end <= 0) return "";
for (int i=0, j=start; i < slice_len; i++, j++)
sliced_str[i] = str[j];
return sliced_str;
}
I can call this as follows:
char * new_string = slice("old string", 3, 5)
Is there a way to be able to "omit" an argument somehow in C? For example, passing something like the following:
char * new_string = slice("old string", 3, NULL)
// NULL means ignore the `end` parameter and just go all the way to the end.
How would something like that be done? Or is that not possible to do in C?
Optional arguments (or arguments that have default values) are not really a thing in C. I think you have the right idea by passing in 'NULL', except for that NULL is equal to 0 and will be interpreted as an integer. Instead, I would recommend changing the argument to a signed integer instead of unsigned, and passing in a -1 as your flag to indicate that the argument should be ignored.
There's only two ways to pass optional arguments in C, and only one is common. Either pass a pointer to the optional argument and understand NULL as not passed, or pass an out-of-range value as not passed.
Way 1:
char * slice(const char * str, const unsigned int *start, const unsigned int *end);
// ...
const unsigned int three = 3;
char * new_string = slice("old string", &three, NULL)
Way 2:
#include <limits.h>
char * slice(const char * str, const unsigned int start, const unsigned int end);
char * new_string = slice("old string", 3, UINT_MAX);
BTW, this example should really be using size_t and SIZE_MAX but I copied your prototype.
The proposed dupe target is talking about vardiac functions, which do have optional arguments, but it's not like what you're asking for. It's always possible in such a function call to determine if the argument is (intended to be) present by looking at the arguments that come before. In this case, that won't help at all.
This question already has answers here:
Why does strchr take an int for the char to be found?
(4 answers)
Closed 6 years ago.
Trying to create a simple function that would look for a single char in a string "like strchr() would", i did the following:
char* findchar(char* str, char c)
{
char* position = NULL;
int i = 0;
for(i = 0; str[i]!='\0';i++)
{
if(str[i] == c)
{
position = &str[i];
break;
}
}
return position;
}
So far it works. However, when i looked at the prototype of strchr():
char *strchr(const char *str, int c);
The second parameter is an int? I'm curious to know.. Why not a char? Does this mean that we can use int for storing characters just like we use a char?
Which brings me to the second question, i tried to change my function to accept an int as a second parameter... but i'm not sure if it's correct and safe to do the following:
char* findchar(char* str, int c)
{
char* position = NULL;
int i = 0;
for(i = 0; str[i]!='\0';i++)
{
if(str[i] == c) //Specifically, is this line correct? Can we test an int against a char?
{
position = &str[i];
break;
}
}
return position;
}
Before ANSI C89, functions were declared without prototypes. The declaration for strchr looked like this back then:
char *strchr();
That's it. No parameters are declared at all. Instead, there were these simple rules:
all pointers are passed as parameters as-is
all integer values of a smaller range than int are converted to int
all floating point values are converted to double
So when you called strchr, what really happened was:
strchr(str, (int)chr);
When ANSI C89 was introduced, it had to maintain backwards compatibility. Therefore it defined the prototype of strchr as:
char *strchr(const char *str, int chr);
This preserves the exact behavior of the above sample call, including the conversion to int. This is important since an implementation may define that passing a char argument works differently than passing an int argument, which makes sense on 8 bit platforms.
Consider the return value of fgetc(), values in the range of unsigned char and EOF, some negative value. This is the kind of value to pass to strchr().
#Roland Illig presents a very good explanation of the history that led to retaining use of int ch with strchr().
OP's code fails/has trouble as follows.
1) char* str is treated like unsigned char *str per §7.23.1.1 3
For all functions in this subclause, each character shall be interpreted as if it had the type unsigned char
2) i should be type size_t, to handle the entire range of the character array.
3) For the purpose of strchr(), the null character is considered part of the search.
The terminating null character is considered to be part of the string.
4) Better to use const as str is not changed.
char* findchar(const char* str, int c) {
const char* position = NULL;
size_t i = 0;
for(i = 0; ;i++) {
if((unsigned char) str[i] == c) {
position = &str[i];
break;
}
if (str[i]=='\0') break;
}
return (char *) position;
}
Further detail
The strchr function locates the first occurrence of c (converted to a char) in the string pointed to by s. C11dr §7.23.5.2 2
So int c is treat like a char. This could imply
if((unsigned char) str[i] == (char) c) {
Yet what I think this is meant:
if((unsigned char) str[i] == (unsigned char)(char) c) {
or simply
if((unsigned char) str[i] == (unsigned char)c) {
I'm currently writing an application where I need a C-function to return an array. I've read that C-functions directly can't return arrays but pointers to arrays, anyhow I still don't get it to work. I'm sending a string with several numerical values that I have to put into an array.
My code looks like this, where the main function is:
int main() {
char arr[3] = {0};
char *str = "yaw22test242test232";
foo(arr,3,str);
printf("%d\n",arr[0]);
return 0;
}
Where I want the foo function to return an array with the numbers 22, 242 and 232 on array positions 0, 1 and 2 respectively. The algorithm in the foo function works properly when used in the main program but not this way. Is there any way to work around this? What am I doing wrong? The foo function looks as follows:
void foo(char *buf, int count, char *str) {
char *p = str;
int k = 0;
while (*p) { // While there are more characters to process...
if (isdigit(*p)) { // Upon finding a digit, ...
double val = strtod(p, &p); // Read a number, ...
//printf("%f\n", val); // and print it.
buf[1-count-k] = val;
k++;
} else { // Otherwise, move on to the next character.
p++;
}
}
}
Well you are going out of bounds here:
buf[1-count-k] = val;
perhaps you mean something like buf[k] = val; and a check if( k >= count ) to end the loop.
Since char *buf usually isn't able to represent values larger than 127, you should use an integer type large enough, or a double, otherwise the assignment buf[*] = val; from a type double to a type char, will cause undefined behavior.
It looks like you want to extract the numbers in the string as doubles, but you're trying to store them in a char array. This doesn't even compile.
So, first, use a proper buffer:
int main() {
double arr[3] = {0};
/* ... */
}
And update the parameter declaration in foo():
void foo(double *buf, int count,char *str) { ... }
And then fix this:
buf[1-count-k] = val;
You probably want something as simple as:
buf[k++] = val;
Finally, you may want to return k so that the caller has a chance to know how many numbers were written into the array. So, foo would look like this:
size_t foo(double *buf, int count,char *str) {
char *p = str;
size_t k = 0;
while (*p) { // While there are more characters to process...
if (isdigit(*p)) { // Upon finding a digit, ...
double val = strtod(p, &p); // Read a number, ...
//printf("%f\n", val); // and print it.
buf[k++] = val;
} else { // Otherwise, move on to the next character.
p++;
}
}
return k;
}
Note that the correct type to index an array is size_t, and not int. size_t is guaranteed to be wide enough to hold the size of any array, so if you want your code to work with arbitrarily long arrays, size_t should be used to index the array.
I would recommend using a vector-like structure instead of an array. There are many implementations of this already (see GLib lists for C). But if you want to 'roll your own', try something similar to this:
typedef struct
{
char** data;
int size;
} str_vector;
Where you can dynamically allocate a str_vector and its data member, and return this. I won't go into too much more detail as there is quite a few tutorials on this on the internet, which I am sure you can bring up in Google/Bing/Whatever in a manner of seconds :)
The purpose of this function is to copy a string into a "buffer" - essentially another string. However, the problem seems overly complicated than what would be practical.
"Copies at most n-1 characters of string in into the buffer pointed to by
out. If n is reached, returns -2. Otherwise, returns -1 for malformed
input and 0 upon successful completion."
This is what I have:
#include <stdio.h>
#include <assert.h>
int copyStringN(register char *in, register char *out, register int n){
//Declarations
int i; //Dummy index
if(!in || !out) return -1;
for(i=0; i<n; i++){
*out++ = *in++;
}
*out = '\0';
return 0;
}
int main(void){
//Declarations
char in[] = "I'm not trying to inject malicious code...\\x29A.";
const int N = sizeof(in);
char out[N];
int err;
//Main execution
printf("\nThis function will copy at most n-1 characters of string into\nthe buffer pointed to by out.\n\n");
err = copyStringN(in, out, N);
assert(!err);
printf("%s\n", out);
printf("\nPlease press enter to exit...");
getchar();
return 0;
}
This general form was suggested, but it seems overly convoluted than what needs to be done. Why would n ever be reached? The execution should stop before n. Furthermore, wouldn't N = sizeof(in) match the length of the original string?
Personally, I would rather use a function closer to
int copyStringN(register char *in, register char *out)
{
if((!in || !out) && (sizeof(in)<=sizeof(out))) return -1;
else{
while(*t++ = *from++);
return 0;
}
}
int main(void){
//Declarations
char in[] = "I'm not trying to inject malicious code...\\x29A.";
const int N = sizeof(in);
char out[N];
int err;
.
.
.
I believe it would have the same effect with less statements. Let me make this more of a question, how could I write a function that copies a string into another array with the protection defined in the prompt? Also, are the two programs that I presented somehow vulnerable in a way I don't recognize?
Constructive input is appreciated.
This is a strange thing in C.
char mole[] = "mole" is not the same as char *mole = "mole"
I just tried:
char *a1 = "mole";
char a2[] = "mole";
printf ("s1: %i s2:%i\n", sizeof(a1), sizeof(a2) );
a1 is a pointer, so 4 or 8 depending on the architecture.
a2 is an array of size 5.
But you can convert a2 to a char* without warnings. But you loose the size.
Your suggested alternative will not work. (sizeof(in)<=sizeof(out) will always be TRUE, because you are comparing pointers (and not arrays), and they are the same size.
If you want to make safe string copy function, you must always pass output buffer length for size checking, and have means to inform user if input was too long for output.
Edit:
Since people have suggested to use strncpy, I will present safer alternative:
int len = snprintf(output, OUTPUT_SIZE, "%s", input);
if(len < 0 || len >= OUTPUT_SIZE) {
// Failed, handle error
}
Fewer statements in your source does not necessarily imply that it is simpler to grasp. The while row in your alternative solution may work, but is doing too many things at the same time for my taste. You are writing code first for other human beings to read, then for a compiler to read.
I like for example making the NULL and \0 checking explicit.
It is also unclear what you are trying to achieve with the sizeof comparison. Besides comparing size of pointers (instead of intended arrays?), I think you meant || instead of &&. If either pointer is NULL it is an error, whatever the size.
int copyStringN(char *in, char *out)
{
if((in == NULL) || (out == NULL)) {
return -1;
} else {
while(*in != '\0') {
*out++ = *in++;
}
*out = '\0';
return 0;
}
}
The compiled code is probably not going to be much different, only the source is more human readable in my opinion.
Then if there happens to be no '\0' in the in string you are going to have problems. I suppose this is the reason for having a length limit n.
while((*in != '\0') && (n-- > 0)) {
*out++ = *in++;
}
*out = '\0';
Note that you would still be in trouble if n is greater than the size of your arrays and you miss a '\0'.
A very similar interface is strncpy. Perhaps the error modes will make more sense after you read the man page.
It is always better to use strncpy to prevent buffer overflow. char * strncpy ( char * destination, const char * source, size_t num ); Also, better to use strlen rather than sizeof. So, Even if the source string is greater than the destination buffer. It will protect the destination buffer from buffer overflow. I would use n as the maximum size of the destination buffer. And In fact make n = strlen(dest_buffer) -1. To accommodate '\0'.
a basic strncpy would look like:
char *strncpy(char *d,const char *s,int n){int i=0;while(n--&&d[i++]=*s++);return d;}
but you could force a null byte at n-1
char *sstrncpy(char *d, const char *s, int n){
int i=0;
while(--n&&d[i++]=*s++);
if(!n)d[i]=0;
return d;
}
I have a javascript file, and I want to translate it in C, I did it but I have a big runtime error.
Everything work well until the end of the function when it return an int.
If you have some ideas where the bug is.
Thanks a lot.
#ifndef max
#define max( a, b ) ( ((a) > (b)) ? (a) : (b) )
#endif
char *substring(size_t start, size_t stop, const char *src, char *dst, size_t size)
{
int count = stop - start;
if ( count >= --size )
{
count = size;
}
sprintf(dst, "%.*s", count, src + start);
return dst;
}
int CrackLog(char log[], char pw[])
{
int tabc=3696619; //7
char tab[]=" azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN0123456789_$&##";
int i,checksum;
checksum=tabc;
int nblog=strlen(log);
int nbpass=6;//6
int sum=1;
int n = max(nblog,nbpass);
for (i=0;i<n;i++)
{
char *to;
to = substring(i, i+1, log, to, sizeof to);
int index1=strcspn(tab, to)+10;
to = substring(i, i+1, pw, to, sizeof to);
int index2=strcspn(tab, to)+10;
sum=sum+(index1*n*(i+1))*(index2*(i+1)*(i+1));
}
if (sum==checksum) {
return 1;
}else
return 0;
}
Forgive my english I am frensh.
Mac Fly
sprintf requires you allocate the memory yourself.
Try changing char *to;
to
char *to = (char*) malloc(sizeof(char)*(stop-start));
where start and stop are the first two arguments to substring
You might have to include stdlib.h if you haven't already
It looks like you are looping over the length of the two parameters log and pw. But since n appears as if it might be set to the maximum of those two lengths, then the substring call will be reading past the end of the shorter buffer at some point. In the given code, nbpass is hard coded to 6, so it is unclear exactly what the intent or result will be. Nonetheless, it seems that could be an issue (maybe you want a min result?).
As tzenes correctly points out, you need to make sure that the dst parameter of the substring call has a valid buffer to use. If you use malloc as he suggests, make sure you free it each time (if it is allocated each iteration).
However, the substring function is only extracting one character at a time. If that is the desired result, then the following might be more efficient:
char to[2];
to[1] = '\0'; // null terminate
for (i=0;i<n;i++)
{
to[0] = log[i];
int index1=strcspn(tab, to)+10;
to[0] = pw[i];
int index2=strcspn(tab, to)+10;
sum=sum+(index1*n*(i+1))*(index2*(i+1)*(i+1));
}