Reverse command-line arguments (C) - c

The overall gist of the program is to accept a command-line argument and for each string to print out backwards with variable length.
For example:
$ ./reversecommand hello 102
dnammocesrever/. olleh 201
I am having difficulty in implementing the thought process into code (e.g. with hello below). Any thoughts?
argc[0] ./reversecommand
argc[1] hello
argc[1][0] h -> argc[1][4] o
argc[1][1] e -> argc[1][3] l
argc[1][2] l -> argc[1][2] l
argc[1][3] l -> argc[1][1] e
argc[1][4] o -> argc[1][0] h
argc[2] 102
argc[3] [null]

#include <stdio.h>
#include <string.h>
static void print_reversed(const char *str, size_t len)
{
const char *ptr = str + len;
while (ptr > str)
putchar(*--ptr);
}
int main(int argc, char **argv)
{
for (int i = 0; i < argc; i++)
{
if (i != 0)
putchar(' ');
print_reversed(argv[i], strlen(argv[i]));
}
putchar('\n');
return 0;
}
There's no need to modify the strings; simply print the characters out one at a time in reverse order.

The logic is fairly straightforward: For each string in argv, reverse it and then print it.
#include <stdio.h>
#include <string.h>
void swap_characters(char *s, char *t) {
char tmp = *s;
*s = *t;
*t = tmp;
}
void reverse_string(char *s, int length) {
for (int i = 0; i < length / 2; ++i)
swap_characters(s + i, s + length - 1 - i);
}
int main(int argc, char **argv) {
for (int i = 0; i < argc; ++i) {
reverse_string(argv[i], strlen(argv[i]));
printf("%s ", argv[i]);
}
printf("\n");
}

Try this code give File name as reverse and put command line argument:-

There are lots of ways to do string reversal, and it is worth spending some time looking into because it is a standard interview question.
a simple implementation for null-terminated strings in C looks like
char * reverse(char * string){
int i;
int len = strlen(string);
for (i = 0; i < len/2; i++){
char c = string[i];
string[i] = string[len - i - 1];
string[len - i - 1] = c;
}
return string;
}
This version does manipulate the string, so we'll make a copy of the string just in case.
Once you have string reversal, you will need to run reverse on each argument, and print it out.
NOTE: arguments in a standard console application like this start with the name of the program as it was typed by the user. So if the program is invoked as ./my-program arg1 arg2, argv[0] will be "./my-program", so we will skip argv[0]
Using this, all you have to do is call reverse on each argument. like so
int main(int argc, char ** argv){
int i;
char * copy;
for ( i = 1; i < argc; i++){ // skip argv[0]
copy = strdup(argv[i]); // copy the string;
copy = reverse(copy);
printf("argv[%d] = \"%s\"\n", i, copy);
free(copy); // clean up the copy
}
}
All together, you get
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * reverse(char * string){
int i;
int len = strlen(string);
for (i = 0; i < len/2; i++){
char c = string[i];
string[i] = string[len - i - 1];
string[len - i - 1] = c;
}
return string;
}
int main(int argc, char ** argv){
int i;
char * copy;
for ( i = 1; i < argc; i++){ // skip argv[0]
copy = strdup(argv[i]); // copy the string;
copy = reverse(copy);
printf("argv[%d] = \"%s\"\n", i, copy);
free(copy); // clean up the copy
}
}

Related

Efficiently replace a substring in a string

I have made two functions that find a substring index and substitute that substring in the string. I'm glad I jury rigged this at all, given that similar questions previously asked were never answered/marked as closed without any help. Is there a cleaner method?
void destroy_substr(int index, int len)
{
int i;
for (i = index; i < len; i++)
{
string[i] = '~';
}
}
void find_substr_index(char* substr)
{
int i;
int j;
int k;
int count;
int len = strlen(substr);
for (i = 0; i < strlen(string); i++)
{
if (string[i] == substr[0])
{
for(j = i, k = 0; k < len; j++, k++)
{
if (string[j] == substr[k])
{
count++;
}
if (count == len)
destroy_substr((j - len + 1), len);
}
j = 0;
k = 0;
count = 0;
}
}
}
Your code seems like you're trying to re-inventing your own wheel.
By using standard C functions, which is strstr() and memset(), you can achieve the same result as you expected.
#include <stdio.h>
#include <string.h>
char string[] = "foobar foobar foobar";
char substr[] = "foo";
char replace = '~';
int main() {
int substr_size = strlen(substr);
// Make a copy of your `string` pointer.
// This is to ensure we can safely modify this pointer value, without 'touching' the original one.
char *ptr = string;
// while true (infinite loop)
while(1) {
// Find pointer to next substring
ptr = strstr(ptr, substr);
// If no substring found, then break from the loop
if(ptr == NULL) { break; }
// If found, then replace it with your character
memset(ptr, replace, substr_size);
// iIncrement our string pointer, pass replaced substring
ptr += substr_size;
}
printf("%s\n", string);
return 0;
}
How about this:
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char string[] = "HELLO hello WORLD world HELLO hello ell";
char substring[] = "ell";
int stringLength = strlen(string);
int substringLength = strlen(substring);
printf("Before: %s\n", string);
if(substringLength <= stringLength)
{
int i;
int j;
for(i = 0, j = stringLength - substringLength + 1; i < j; )
{
if(memcmp(&string[i], substring, substringLength) == 0)
{
memset(&string[i], '~', substringLength);
i += substringLength;
}
else
{
i++;
}
}
}
printf("After: %s\n", string);
return 0;
}
Key ideas are:
You only need to scan the string (stringLength - substringLength) times
You can use functions from string.h to do the comparison and to replace the substring
You can copy the new string in place. If you want to support insertion of longer strings you will need to manage memory with malloc()/realloc(). If you want to support insertion of smaller strings you'll need to advance the pointer to the beginning by the length of the replacement string, copy the rest of the string to that new location, then zero the new end of the string.
#include <stdio.h>
#include <string.h>
#include <err.h>
int main(int argc, char **argv)
{
char *str = strdup("The fox jumps the dog\n");
char *search = "fox";
char *replace = "cat";
size_t replace_len = strlen(replace);
char *begin = strstr(str, search);
if (begin == NULL)
errx(1, "substring not found");
if (strlen(begin) < replace_len)
errx(1, "replacement too long");
printf("%s", str);
memcpy(begin, replace, replace_len);
printf("%s", str);
return 0;
}

Converting lowercase letters to uppercase

I have a program to reverse a string and convert it to uppercase. If I write helloworld!, the output must be !DLROWOLLEH. But if I write hello world! the output is !DLRO. Could you tell me where the possible problem is?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
char * reverse(const char * text)
{
if (text==NULL)
return NULL;
int length = strlen(text);
char * reversed_string = malloc(length+1);
for(int i = 0; i < length/2; ++i)
{
reversed_string[i] = text[(length-1) - i];
reversed_string[(length-1) - i] = text[i];
}
reversed_string[length] = '\0';
//upper(reversed_string);
return reversed_string;
}
void upper(char *str1)
{
while(*str1!='\0')
{
if(*str1>96&&*str1<123)
*str1=*str1-32;
str1++;
}
}
int main(int argc, char * argv[])
{
char p[256];
fgets(p, sizeof(p), stdin);
char * rev_str = reverse(p);
upper(rev_str);
printf("%s\n", rev_str);
rev_str = 0;
return 0;
}
The problem is here
for(int i = 0; i < length/2; ++i)
It length is an odd number (like 11 in your example), this will implicitly round down, and as a consequence, you never write to the middle element in the string. Un your case, this happened to be 0, but that is not guaranteed to be so, so any character might have appeared there, instead of terminating the string early.
The easiest fix would be changing that to (length+1)/2, but that will have the effect that you write the middle element twice.
Actually, I think it is much easier if you just reverse the string just by iterating over it in one direction instead of from both.
I've modified your code and it works as expected.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
char * reverse(const char * text)
{
if (text==NULL)
return NULL;
unsigned long length = strlen(text);
char * reversed_string = malloc(length+1);
for(int i = 0; i < length; ++i)
{
reversed_string[i] = text[(length-1) - i];
//reversed_string[(length-1) - i] = text[i];
}
reversed_string[length] = '\0';
//upper(reversed_string);
return reversed_string;
}
void upper(char *str1)
{
while(*str1!='\0')
{
if(*str1>96&&*str1<123)
*str1=*str1-32;
str1++;
}
}
int main(int argc, char * argv[])
{
char p[256];
fgets(p, sizeof(p), stdin);
char * rev_str = reverse(p);
printf("%s\n", rev_str);
upper(rev_str);
printf("%s\n", rev_str);
rev_str = 0;
return 0;
}

C - strcat in for loop

I m writing a little C program and want to know why my output in the console is "0", "0" [...]? The output i expect is "ab", "ac", [...].
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i;
int j;
char string[] = "abc";
char output[8];
int length = size(&string[0]);
for(i=0; i<length; i++) {
for(j=0; j<length; j++){
char a = string[i];
strcat(output, &a);
char b = string[j];
strcat(output, &b);
printf("%c\n", output);
}
}
return 0;
}
Mistake #1. You have not initialised output[] so strcat() will not validly find a nul terminator to append to.
output[0] = 0;
Mistake #2. strcat() isn't the right way of appending chars anyway.
Mistake #3. Your loop controls aren't right. See below.
Mistake #4. Your length is the size of a char* pointer.
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i, j;
char string[] = "abc";
char output[8];
int length = strlen (string); // corrected
for(i=0; i<length-1; i++) { // amended loop
for(j=i+1; j<length; j++) { // amended loop
output[0] = string [i];
output[1] = string [j];
output[2] = 0; // string terminator
printf("%s\n", output); // uses string type not char
}
}
return 0;
}
Program output:
ab
ac
bc
If I have understood correctly what you are trying to do then the program will look the following way
#include <stdio.h>
int main(int argc, char *argv[])
{
char string[] = "abc";
char output[3];
size_t length = sizeof( string ) - 1;
for ( size_t i = 0; i < length; i++ )
{
for ( size_t j = 0; j < length; j++ )
{
if ( i != j )
{
output[0] = string[i];
output[1] = string[j];
output[2] = '\0';
puts( output );
}
}
}
return 0;
}
The output is
ab
ac
ba
bc
ca
cb
If your compiler does not allow to declare variables within the control statement of the loop then you can declare i and j in the beginning of the program.
size_t i, j;
If you want to include combinations like "aa" then you simply may remove the if statement withing the inner loop.
char a = string[i];
strcat(output, &a);
leads to undefined behavior since strcat expects a null terminated string in the second argument. Same thing applies to:
char b = string[j];
strcat(output, &b);
Perhaps you meant to use:
output[0] = a;
output[1] = b;
output[2] = '\0';
Here's the updated for loop:
for(i=0; i<length; i++) {
for(j=0; j<length; j++){
output[0] = a;
output[1] = b;
output[2] = '\0';
printf("%s\n", output);
// ^^ use %s to print a string, not %c.
}
}
If you want to use strcat you must know that it expects a string not a character and there is an important difference, when you pass &a strcat thinks it is the address of a pointer to a string, and you should get most likely a segmentation fault, here I show your own code, modified to use strcat but you don't really need it for this task.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i;
int j;
char string[] = "abc";
int length = strlen(&string[0]);
for(i = 0 ; i < length ; i++)
{
for(j= i + 1 ; j < length ; j++)
{
/* initialize output to 0 more importantly to have a terminating null byte */
char output[3] = {0};
/*
* create a string and initialize it with 2 char's
* - the first one, the one you want to append to output
* - the second one is required by strcat, to mark the end of the string
*/
char a[2] = {string[i], 0};
strcat(output, a);
/* same as above */
char b[2] = {string[j], 0};
strcat(output, b);
printf("%s\n", output);
}
}
return 0;
}
you could do this without strcat unless you are trying to learn how to use strcat, this is an example of how to do it without strcat.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i;
int j;
char string[] = "abc";
int length = strlen(&string[0]);
for(i = 0 ; i < length ; i++)
{
for(j= i + 1 ; j < length ; j++)
{
char output[3] = {string[i], string[j], 0};
printf("%s\n", output);
}
}
return 0;
}

Trouble with argv and char

Since two hours, i'm trying to modify my program to give it arguments (argv) instead of a char.
So, here is my current code:
int i;
char ret[81];
*ret = 1;
for (i = 0; i < argc; i++)
{
ret[0] = '\0';
strcat(ret,argv[i]);
}
This code concatenate all args into a char, printf is returning the good same result as my old char argument, but not working in my code:
char test[] = "9...7....2...9..53.6..124..84...1.9.5.....8...31..4.....37..68..9..5.74147.......";
solve(test); //working
solve(ret); //not working
my app is launched like that:
./a.out "9...7...." "2...9..53" ".6..124.." "84...1.9." "5.....8.." ".31..4..." "..37..68." ".9..5.741" "47......."
Soooo, if anyone understand my problem i'll probably need some help :D
sample code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void solve(char *data){
static const char *result = "9...7....2...9..53.6..124..84...1.9.5.....8...31..4.....37..68..9..5.74147.......";
if(strcmp(result, data) == 0)
printf("working\n");
else
printf("not working\n");
}
int main(int argc, char *argv[]){
int i, total_length = 0;
for(i = 1; i < argc; ++i){
total_length += strlen(argv[i]);
}
char ret[total_length + 1];
ret[0] = '\0';
for(i = 1; i < argc; ++i){
strcat(ret, argv[i]);
}
char test[] = "9...7...."
"2...9..53"
".6..124.."
"84...1.9."
"5.....8.."
".31..4..."
"..37..68."
".9..5.741"
"47.......";
solve(test);
solve(ret);
return 0;
}

Concatenate all arguments (except the executable name)

Is there a C function that can concatenate all the passed arguments (except the name of the executable) into a char* and return it?
Try that:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv) {
unsigned int i;
size_t len = 0;
char *_all_args, *all_args;
for(i=1; i<argc; i++) {
len += strlen(argv[i]);
}
_all_args = all_args = (char *)malloc(len+argc-1);
for(i=1; i<argc; i++) {
memcpy(_all_args, argv[i], strlen(argv[i]));
_all_args += strlen(argv[i])+1;
*(_all_args-1) = ' ';
}
*(_all_args-1) = 0;
printf("All %d args: '%s'\n", argc, all_args);
free(all_args);
return 0;
}
Why would there be ? Just use strcat in a loop.
Something like this? No guarantees that this will compile.
#include <string.h>
#include <stdio.h>
int main(int argc, char ** argv) {
int i;
int len = 1;
char * str;
for (i = 1; i < argc; i++) {
len += strlen(argv[i]);
}
str = malloc(sizeof(char)*len);
str[0] = '\0';
for (i = 1; i < argc; i++) {
strcat(str, argv[i]);
}
//Use str for whatever you want
printf("My string is %s\n", str);
free(str);
}
I don't think there's such a function, but if I'm not wrong, you just have to :
get the length : len = strlen(argv[1]) + strlen(argv[2]) + ... and check for overflow
use malloc : malloc(len + 1) * sizeof(char))
set your_copy[0] to '\0'
use strcat(your_copy, argv[1]), strcat(your_copy, argv[2])... for each remaining argv[]
EDIT : Oh, the previous answer may be better. ;)

Resources