I want to write a program that when I am on terminal and write prog.exe -u word will transform word to uppercase otherwise skip the process. but when I compile the code below, I get nothing on screen and I couldn't figure out why the error occurs.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
char u[] = "-u";
void upper(const char *src, char *dest);
int main(int argc, char const *argv[]) {
if (argc < 3) {
printf("Input at least 3 argument!\n");
} else
if (!(strcmp(argv[1], u))) {
char *output;
upper(argv[2], output);
printf("%s\n", output);
} else {
printf("No option\n");
}
return 0;
}
void upper(const char *src, char *dest) {
while (*src) {
if (*src >= 97 && *src <= 122) {
*dest = *src - 32;
} else {
*dest = *src;
}
src++;
dest++;
}
*dest = *src;
}
The pointer output declared like
char * output;
is uninitialized and has an indeterminate value.
So using it in the function upper invokes undefined behavior.
Instead of the pointer you should use a character array large enough to store the passed string to the function.
If the compiler supports variable length arrays then you can write
char output[ strlen( argv[2] ) + 1 ];
And this if statement
else if( strcmp(argv[1],u) == 0 ){
will be more readable than this if statement
else if(!(strcmp(argv[1],u))){
Within the function it will be at least better to use character symbols 'a' and 'z' instead of the magic numbers 97 and 122 in the if statement
if(*src >= 97 && *src <= 122){
*dest = *src - 32;
}
Though it is even better to use standard function islower and toupper declared in the header <ctype.h>.
The function can be declared and defined the following way
#include <ctype.h>
//...
char * upper( char *dest, const char *src )
{
char *result = dest;
do
{
if ( islower( ( unsigned char )*src ) )
{
*dest++ = toupper( ( unsigned char )*src );
}
else
{
*dest++ = *src;
}
} while ( *src++ );
return result;
}
void upper(const char *src, char *dest) {
char *tmp = dest; // hold pointer
while(*src) {
*dest = (*src >= 97 && *src <= 122) ? *src - 32 : src;
++src; ++dest;
}
*dest = '\0'; // end of string
dest = tmp;
}
The program has undefined behavior because you attempt to store the converted string to an uninitialized pointer output.
Note that using hard coded constants such as 97, 122 and 32 is both confusing and non portable to non-ASCII environments. You should use the macros and functions from <ctype.h> for readability and portability.
You could simply modify the argument string in place this way:
#include <ctype.h>
#include <stdio.h>
void upper(char *str);
int main(int argc, char *argv[]) {
if (argc < 3) {
printf("Input at least 3 arguments!\n");
} else
if (!(strcmp(argv[1], "-u"))) {
printf("%s\n", upper(argv[2]));
} else {
printf("No option\n");
}
return 0;
}
char *upper(char *str) {
for (char *p = str; *p; p++) {
*p = toupper((unsigned char)*p);
}
return str;
}
Related
I have to make a function, that will code my sentence like this: I want to code all words with an o, so for example I love ice cream becomes I **** ice cream.
But my function ignores the result of strchr. And I don't know why.
This is my code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define LEN 1000
char *Shift(char *str, char *let) {
const char *limits = " ,-;+.";
char copy[LEN];
strcpy(copy, str);
char *p;
char *ptr;
ptr = strtok(copy, limits);
for (int j = 0; ptr != NULL; ptr = strtok(NULL, limits), ++j) {
int len = 0;
if (strchr(ptr, let) != NULL) {
p = strstr(str, ptr);
for (int i = 0; i < strlen(ptr); i++) {
p[i] = "*";
}
}
}
return str;
}
int main() {
char *s = Shift("I love my cocktail", "o");
puts(s);
}
Expected output is: I **** my ********
but I've got just printed the original string
For starters the function strchr is declared like
char *strchr(const char *s, int c);
that is its second parameter has the type int and the expected argument must represent a character. While you are calling the function passing an object of the type char * that results in undefined behavior
if (strchr(ptr, let) != NULL) {
It seems you mean
if (strchr(ptr, *let) != NULL) {
Also you may not change a string literal. Any attempt to change a string literal results in undefined behavior and this code snippet
p = strstr(str, ptr);
for (int i = 0; i < strlen(ptr); i++) {
p[i] = "*";
}
tries to change the string literal passed to the function
char *s = Shift("I love my cocktail", "o");
And moreover in this statement
p[i] = "*";
you are trying to assign a pointer of the type char * to a character. At least you should write
p[i] = '*';
If you want to change an original string you need to store it in an array and pass to the function the array instead of a string literal. For example
char s[] = "I love my cocktail";
puts( Shift( s, "o" ) );
Pay attention to that there is no great sense to declare the second parameter as having the type char *. Declare its type as char.
Also the function name Shift is confusing. You could name it for example like Hide or something else.
Here is a demonstration program.
#include <stdio.h>
#include <string.h>
char * Hide( char *s, char c )
{
const char *delim = " ,-;+.";
for ( char *p = s += strspn( s, delim ); *p; p += strspn( p, delim ) )
{
char *q = p;
p += strcspn( p, delim );
char *tmp = q;
while ( tmp != p && *tmp != c ) ++tmp;
if ( tmp != p )
{
for ( ; q != p; ++q ) *q = '*';
}
}
return s;
}
int main( void )
{
char s[] = "I love my cocktail";
puts(s);
puts( Hide( s, 'o' ) );
}
The program output is
I love my cocktail
I **** my ********
The for loop
for ( ; q != p; ++q ) *q = '*';
within the function can be rewritten as a call of memset
memset( q, '*', p - q );
There are multiple problems:
copying the string to a fixed length local array char copy[LEN] will cause undefined behavior if the string is longer than LEN-1. You should allocate memory from the heap instead.
you work on a copy of the string to use strtok to split the words, but you do not use the correct method to identify the parts of the original string to patch.
you should pass a character to strchr(), not a string.
patching the string with p[i] = "*" does not work: the address of the string literal "*" is converted to a char and stored into p[i]... this conversion is meaningless: you should use p[i] = '*' instead.
attempting to modify a string literal has undefined behavior anyway. You should define a modifiable array in main and pass the to Shift.
Here is a corrected version:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *Shift(char *str, char letter) {
const char *limits = " ,-;+.";
char *copy = strdup(str);
char *ptr = strtok(copy, limits);
while (ptr != NULL) {
if (strchr(ptr, letter)) {
while (*ptr != '\0') {
str[ptr - copy] = '*';
ptr++;
}
}
ptr = strtok(NULL, limits);
}
free(copy);
return str;
}
int main() {
char s[] = "I love my cocktail";
puts(Shift(s, 'o'));
return 0;
}
The above code still has undefined behavior if the memory cannot be allocated. Here is a modified version that operates in place to avoid this problem:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
char *Shift(char *str, char letter) {
char *ptr = str;
while ((ptr = strchr(ptr, letter)) != NULL) {
char *p = ptr;
while (p > str && isalpha((unsigned char)p[-1]))
*--p = '*';
while (isalpha((unsigned char)*ptr)
*ptr++ = '*';
}
return str;
}
int main() {
char s[] = "I love my cocktail";
puts(Shift(s, 'o'));
return 0;
}
Note that you can also search for multiple characters at a time use strcspn():
#include <ctype.h>
#include <stdio.h>
#include <string.h>
char *Shift(char *str, const char *letters) {
char *ptr = str;
while (*(ptr += strcspn(ptr, letters)) != '\0') {
char *p = str;
while (p > str && isalpha((unsigned char)p[-1]))
*--p = '*';
while (isalpha((unsigned char)*ptr)
*ptr++ = '*';
}
return str;
}
int main() {
char s[] = "I love my Xtabentun cocktail";
puts(Shift(s, "oOxX"));
return 0;
}
I just started in C and this is a beginner question. But is there any way to copy a string without allocating memory beforehand?
I want to reproduce the strcopy function inbuilt in C with the same structure (char *strcpy(char *src, char *dest);). I got it to work with declaring the char pointer in the function itself and then returning it. It works also with the original structure as strcpy if I allocate the memory beforehand.
#include <stdlib.h>
char *strcopy(char *src, char *dest)
{
int i = 0;
while (src[i] != '\0')
{
dest[i] = src[i];
i++;
}
dest[i] = '\0';
return (dest);
}
int str_size(char *str)
{
int i = 0;
while (str[i] != '\0')
i++;
return (i);
}
int main(int argc, char **argv)
{
char *src = argv[1];
char *dest = (char*)malloc(str_size(src));
dest = strcopy(src, dest);
return (0);
}
So is it somehow possible to copy a string without allocating memory beforehand and without changing my function-head?
If you want to avoid dynamic allocation, use static allocation:
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 1024
char *strcopy(char *src, char *dest)
{
int i = 0;
while (src[i] != '\0')
{
dest[i] = src[i];
i++;
}
dest[i] = '\0';
return (dest);
}
int str_size(char *str)
{
int i = 0;
while (str[i] != '\0')
i++;
return (i);
}
int main(int argc, char **argv)
{
char *src = argv[1];
char dest[BUFFER_SIZE];
if(strlen(src) >= BUFFER_SIZE){
return -1;
}
else{
dest = strcopy(src, dest);
}
return 0;
}
Hello I have a problem with strchr() because yea it will return the pointer to the first occurance of the character but how do I get the index from that to be able to change it? and how can I change one character to two characters?
So I need to change every 'x' in the src to 'ks' in the dest.
My code:
#include <stdio.h>
#include <string.h>
void antikorso(char *dest, const char *src) {
strcpy(dest, src);
if (strchr(dest, 'x')) {
}
printf("\n%s", dest);
}
int main(void) {
const char *lol = "yxi yxi";
char asd[1000];
antikorso(asd, lol);
}
You can do:
void antikorso(char *dest, const char *src) {
const char *p = src;
int i;
for (i = 0; *p != '\0'; i++, p++) {
if (*p != 'x') {
dest[i] = *p;
} else {
dest[i++] = 'k';
dest[i] = 's';
}
}
dest[i] = '\0';
printf("\n%s", dest);
}
following lines of code might be helpful :
#include <stdio.h>
#include <string.h>
void antikorso(char *dest, const char *src) {
int j=0;
for(int i=0;i<strlen(src);i++)
{
if (src[i] == 'x')) {
dst[j]='k';
j++;
dst[j] = 's';
j++;
}
else
{
dst[j] = stc[i];
j++;
}
i++;
}
dst[j] = '\0';
printf("\n%s", dest);
return dest;
}
int main(void) {
const char *lol = "yxi yxi";
char asd[1000];
antikorso(asd, lol);
}
You may not need the index, just a pointer. The "index" would be the offset from the beginning, so dest[i], which is the same as dest + i, which is the address of dest, plus i characters further. So you can use:
char *cp;
if (cp=strchr(dest, 'x')) {
*cp= 'y';
But if you do want the index, it is just
if (cp=strchr(dest, 'x')) {
int i = cp - dest;
Other answers not being incorrect, just want to address an important issue: You are not safe from undefined behaviour by writing past the end of your target buffer (same problem as with so many stdlib functions like strcpy or strcat nowadays considered insecure)! So I strongly recommend modifying your function signature (if you have the freedom to do so):
size_t antikorso(char* dest, size_t length, const char* src)
// ^^ ^^
{
char* d = dest;
char* end = d + length;
for(; *src; ++src, ++d)
{
// not much different than the other answers, just the range checks...
if(d == end)
break;
*d = *src;
if(*d == 'x')
{
*d = 'k'
if(++d == end)
break;
*d = 's';
}
}
// now null-terminate your string;
// first need to get correct position, though,
// in case the end of buffer has been reached:
d -= d == end;
// this might possibly truncate a trailing "ks";
// if not desired, you need extra checks...
*d = 0;
return d - dest;
}
The return value does not add anything to safety, but prevents you from having to call strlen on the output, once written...
If strchr returns a valid address, you can use pointer arithmetic to get the index, by subtracting the "base address" - that is, the pointer to the first element of the array.
#include <string.h>
#include <stddef.h> // NULL, ptrdiff_t
const char* result = strchr(dest, 'x');
if ( result != NULL)
{
ptrdiff_t index = result - dest;
... // do stuff with index
}
ptrdiff_t is a standard C integer type suitable for expressing the result of pointer arithmetic.
I'm trying to convert a string containing a number. The number is thousand separated with a dot. I've made a simple solution with sscanf(input, "%i.%i", &first, %second); return first * 1000 + second;
This works alright, but it has its limitations as it only works for numbers below 1.000.000. I've tried making this recursive, but my program wont compile. Maybe one of you guys, can see whats wrong.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* concat(const char *s1, const char *s2) {
char *result = malloc(strlen(s1)+strlen(s2)+1);//+1 for the zero-terminator
strcpy(result, s1);
strcat(result, s2);
return result;
}
char *convert_spectators( char *input) //
{
char fir[3], sec[100];
int scan_res = sscanf(input, "%3[0123456789]%*[^0123456789]%s", fir, sec);
if (scan_res == 2) {
return concat(fir, convert_spectators(sec));
} else if (scan_res == 1) {
return fir;
}
}
int main() {
printf("Result: %i\n", atoi(convert_spectators("123.456.789")));
return 1;
}
from convert_spectators() you are returning "fir", which is a local array. It is wrong. I modified your code and passing fir and sec from calling function.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* concat(const char *s1, const char *s2) {
char *result = malloc(strlen(s1)+strlen(s2)+1);//+1 for the zero-terminator
strcpy(result, s1);
strcat(result, s2);
return result;
}
char *convert_spectators( char *input, char *fir, char *sec) //
{
int scan_res = sscanf(input, "%3[0123456789]%*[^0123456789]%s", fir, sec);
if (scan_res == 2) {
char firTemp[4] = "";
char secTemp[100] = "";
return concat(fir, convert_spectators(sec, firTemp, secTemp));
} else if (scan_res == 1) {
return fir;
} else {
printf("Something wrong, scan_res[%d]\n", scan_res);
return NULL;
}
}
int main() {
char fir[4] = "";
char sec[100] = "";
printf("Result: %i\n", atoi(convert_spectators("123.456.789", fir, sec)));
return 1;
}
This can be accomplished without scanf
int convert(char *s, int n) {
if (!*s || n >= 1000000000)
return n;
if (*s >= '0' && *s <= '9')
n = n * 10 + *s - 48;
return convert(s+1, n);
}
int main() {
char *str = "123.456.789";
printf("%d\n", convert(str, 0));
}
This will just parse through the string, and skip any characters that aren't digits. And stop at the end of the string or when result overflows 32 bits.
As mentioned, your way of concatenating each substring and converting to an integer is fine, but you are returning a local array in your function convert_spectators(). You need to declare that array locally before you call the function, or make it global.
I have a string in my program where in which it need to be altered with another string value before a "/".
Source String : qos-tree/output_rate
Target String : qos-tree-2/output_rate
#include <stdio.h>
#include <string.h>
void append(char* s, char c)
{
int len = strlen(s);
s[len] = c;
s[len+1] = '\0';
}
int main(void)
{
char str[256] = "qos-tree/output_rate";
char c = "a";
append(str, c);
printf("%s\n", str);
return 0;
}
This is what i have done so far,I think the logic is wrong here.Can anyone guide me to correct it?
Once the execution is completed the source string should have a "-2" before the "/"
void insert_before_ch(char *s, const char *ins, char c){
char *p = strchr(s, c);
if(p){
size_t len = strlen(ins);
memmove(p + len, p, strlen(p)+1);
memcpy(p, ins, len);
}
}
int main(void){
char str[256] = "qos-tree/output_rate";
insert_before_ch(str, "-2", '/');
printf("%s\n", str);
return 0;
}
In your attempt, you don't look for a slash and I do not see any "-2" anywhere.
Try this instead:
#include <stdio.h>
#include <string.h>
void append(char* s, char del, char* substring) {
char origin[256];
strcpy(origin, s);
int i = 0, j = 0, z = 0;
for(; origin[i]; ++i) {
if(origin[i] != del) {
s[j++] = origin[i];
} else {
for(; substring[z]; ++z) {
s[j++] = substring[z];
}
s[j++] = origin[i];
}
}
s[j] = '\0';
}
int main(void) {
char str[256] = "qos-tree/output_rate";
char del = '/';
char* substring = "-2";
append(str, del, substring);
printf("%s\n", str);
return 0;
}
The logic is that inside the function we use origin array to remember the actual contents of the array and then we copy from origin to s (which is the actual array of main()). If we find our delimiter del, then we copy the substring in that position and continuing with copying.
Note that the length of the array should be enough to store the resulted string. In this case, it is.
I think you should make your function work with dynamic allocation, because inserting characters into the string will make the resulting string larger, so this is my suggestion
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void insert(char **str, char chr, unsigned int position)
{
int length;
char *ptr;
if (str == NULL)
return;
length = strlen(*str);
if (position >= length)
return;
ptr = realloc(*str, 2 + length);
if (ptr == NULL)
return;
*str = ptr;
memmove(ptr + position + 1, ptr + position, length - position + 1);
ptr[position] = chr;
}
int main(void)
{
const char *source = "qos-tree/output_rate";
size_t length = strlen(source);
char *str = malloc(1 + length);
if (str == NULL)
return -1;
strcpy(str, source);
insert(&str, '-', 8);
insert(&str, '2', 9);
printf("%s\n", str);
free(str);
return 0;
}
first of all thist char c = "a" should be replace with this char c = 'a'; because c is a character not a string
as for your problem I didn't realy see the relation between what your code is doing with what you said you wanted to do , but here a piece of code to achieve what , I think , you want to do :
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void append(char* str , char c)
{
char firststr[60];
char therest[30];
strcpy(firststr , strtok(str , "/"));
strcpy(therest , strtok(NULL , "/"));
strcat(firststr , &c);
strcat(firststr , "/");
strcat(firststr , therest);
strcpy(str , firststr);
}
int main(void)
{
char str[60] = "qos-tree/output_rate";
char c = '2';
append(str , c);
printf("%s\n" , str);
}
there you go I think this is what you wanted to do you can modify the array sizes to fit your needs