Concatenate first characters from a command line argument in c - c

I have tried this solution, but don't know why it is giving segmentation fault.
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char st[1000]="";
for (int i=1; i<argc; i++)
{
strcat(st,argv[i][0]);
strcat(st,". ");
}
printf("%s", st);
return 0;
}

A solution without using any string-library functions at all might look like:
#include <stdio.h>
#define ARGV_MAX (5) /* Adjust this to match the maximum number of arguments
to be processed. */
#define RESULT_STR_MAX (3*ARGV_MAX +1) /* The chararacters per arg per maximum arguments
to be processed +1 for the 0-terminator. */
int main(int argc, char *argv[])
{
char st[RESULT_STR_MAX] = "";
size_t string_index = 0;
size_t argv_index = 1; /* Skip argv[0] below as it does not carry an
argument, but the program's name. */
while ((size_t) argc > argv_index
&& RESULT_STR_MAX > string_index /* in fact this or
&& ARGV_MAX >= argv_index) this would do. */
{
st[string_index] = argv[argv_index][0];
string_index++;
st[string_index] = '.';
string_index++;
st[string_index] = ' ';
string_index++;
argv_index++;
}
st[string_index] = '\0'; /* Add the '0'-terminator
to make the char array a "string".
(not necessary as st got initialised to all 0s).*/
if (ARGV_MAX < argv_index)
{
printf("Ignored the last %d argument(s).\n", argc - ARGV_MAX - 1);
}
puts(st);
return 0;
}
Below another approach using strcat():
#include <stdio.h>
#define ARGV_MAX (5) /* Adjust this to match the maximum number of arguments
to be processed. */
#define RESULT_STR_MAX (3*ARGV_MAX +1) /* The chararacters per arg per maximum arguments
to be processed +1 for the 0-terminator. */
int main(int argc, char *argv[])
{
char st[RESULT_STR_MAX] = "";
size_t argv_index = 1; /* Skip argv[0] below as it does not carry an
argument, but the program's name. */
while ((size_t) argc > argv_index
&& ARGV_MAX >= argv_index)
{
strcat(st, (char[2]){argv[argv_index][0]});
strcat(st, ". ");
argv_index++;
}
if (ARGV_MAX < argv_index)
{
printf("Ignored the last %d argument(s).\n", argc - ARGV_MAX - 1);
}
puts(st);
return 0;
}

Change this statement
strcat(st,argv[i][0]);
to
strncat(st, &argv[i][0], 1);
or
strncat(st, argv[i], 1);
In the original statement the function considers the character argv[i][0] as a pointer value. So the call has undefined behavior.
Or you can use a straightforward approach without using string functions. For example
#include <stdio.h>
int main( int argc, char * argv[] )
{
char st[1000];
size_t i = 0;
for ( int j = 1; j < argc; j++ )
{
st[i++] = *argv[j];
if ( j + 1 != argc )
{
st[i++] = ',';
st[i++] = ' ';
}
}
st[i] = '\0';
puts( st );
return 0;
}

try this:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]){
char st[1000]="";
--argc, ++argv;//skip first.
char *p = st;
for (int i = 0; i < argc; i++){
if(i){//between ?
strcpy(p, ". ");
p += 2;
}
*p++ = argv[i][0];//copy one character
}
printf("%s\n", st);
return 0;
}

Related

why do I get "Segmentation fault" when assigning values to array of pointers

I have this peace of C Programming code to take multiple literal strings from the user and store each address to each pointer and print out the value
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *ptr[3];
int i = 0;
for (; i < 3; i++) {
printf("ptr_%d: ", i + 1);
fgets(ptr[i], 15, stdin);
ptr[i][strlen(ptr[i]) - 1] = 0;
puts(ptr[i]);
}
return 0;
}
However, only the first one is printed. Here is the output
ptr_1: first line
first line
Segmentation fault
[Program finished]
I want the same result that is produced Here
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *ptr[] = {
"first line",
"second line",
"third line"
};
puts(ptr[0]);
puts(ptr[1]);
puts(ptr[2]);
return 0;
}
output
first line
second line
third line
[Program finished]
Thanks in advance
fgets(ptr[i], 15, stdin);
You've declared an array of three pointers:
char *ptr[3];
But none of those actually point to buffers of memory.
You can either create those buffers automatically:
char ptr[3][15];
Or dynamically with malloc.
char *ptr[3];
for (size_t i = 0; i < 3; i++) {
ptr[i] = malloc(15);
}
If you do this, make sure to free the memory you've allocated.
If you are running gcc (with glibc 2.7 or greater), you can use the m modifier with scanf to allocate memory:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *ptr[3];
for (i = 0; i < 3; i++) {
printf("ptr_%d: ", i + 1);
while (scanf(" %m[^\n]",&ptr[i]) != 1)
printf("Try again: ");
puts(ptr[i]);
}
for (; i < 3; i++)
free(ptr[i]);
return 0;
}
And be sure to free the memory when you are done with it.
You'd probably want to put the scanf section of this code into a function but here is the smallest change to your existing sample that should work.
$ cat allocinput.c
#include <stdio.h>
#include <string.h>
#define MAX_LEN 80
int main(int argc, char *argv[])
{
char c;
char ptr[3][MAX_LEN];
int i = 0;
for (;i<3;i++) {
printf("ptr_%d: ", i + 1);
// could overflow if the user types more than MAX_LEN characters
char *p = ptr[i];
while (scanf("%c", &c) && (p - ptr[i] < MAX_LEN)) {
if (c == '\n') break;
*p++ = c;
*p = 0;
}
puts(ptr[i]);
}
return 0;}
$ gcc -Wall allocinput.c
$ ./a.out
ptr_1: first line
first line
ptr_2: second line
second line
ptr_3: third line
third line
$
P.S. I recommend astyle to clean up the formatting:
$ astyle allocinput.c
Formatted /tmp/overflow/allocinput.c
$ cat allocinput.c
#include <stdio.h>
#include <string.h>
#define MAX_LEN 80
int main(int argc, char *argv[])
{
char c;
char ptr[3][MAX_LEN];
int i = 0;
for (; i<3; i++) {
printf("ptr_%d: ", i + 1);
// could overflow if the user types more than MAX_LEN characters
char *p = ptr[i];
while (scanf("%c", &c) && (p - ptr[i] < MAX_LEN)) {
if (c == '\n') break;
*p++ = c;
*p = 0;
}
puts(ptr[i]);
}
return 0;
}

Custom Concatenate in C

I'm trying to write my own concatenate program. What I'm doing is getting two strings as input from argv, creating a third empty character array that holds the length of argv[1] + argv[2], and then use two for loops to insert the characters from each argv string into the third string.
My first for loop seems to be working fine buy my second for loop isn't doing anything. Any ideas?
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *string1 = argv[1];
char *string2 = argv[2];
int string1Len = strnlen(string1, 50);
int string2Len = strnlen(string2, 50);
char string3[string1Len + string2Len + 1];
for (int i = 0; i <= string1Len; i++)
{
string3[i] = string1[i];
}
for(int i = (string1Len + 1); i <= (string1Len + string2Len); i++)
{
string3[i] = string2[i];
}
string3[string1Len + string2Len + 1] = '\0';
printf("%s %d %d\n", string3, string1Len, string2Len);
return 0;
}
You can simplify (and optimize) it by using the memcpy function
int main(int argc, char **argv) {
if (argc < 3) return 1;
const char *string1 = argv[0];
const char *string2 = argv[1];
const size_t string1Len = strlen(string1);
const size_t string2Len = strlen(string2);
char *string3 = malloc((string1Len + string2Len + 1) * sizeof(*string3));
memcpy(string3, string1, string1Len * sizeof(*string1));
memcpy(string3 + string1Len, string2, (string2Len + 1) * sizeof(*string2));
printf("%s %zu %zu", string3, string1Len, string2Len);
free(string3);
return 0;
}
And as the others said, pay attention to the nul terminator
Your second for loop "did nothing" because the first one worked up to the \0 character and included it in string3, so it's better to set the condition that the for loop works up to that character
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *string1 = argv[1];
char *string2 = argv[2];
int string1Len = strlen(string1);
int string2Len = strlen(string2);
int i;
char string3[string1Len + string2Len +1];
for (i = 0; string1[i]!='\0'; i++)
{
string3[i] = string1[i];
}
string3[i]=' '; //with space
++i;
for(int j = 0; string2[j]!='\0'; j++)
{
string3[i] = string2[j];
i++;
}
string3[string1Len + string2Len + 1] = '\0';
printf("%s %d %d\n", string3, string1Len, string2Len);
return 0;
}
There are two main issues in your code. Your first for loop copies the nul terminator from string1; so, anything you then add to your string3 after that will simply be ignored by functions like printf, because they see that nul as marking the end of the string.
In your second for loop, you have the same problem and, more critically, the i index you use is not valid for string2, as you have added the length of string1 to it.
Also, note that arrays in C start at zero, so you shouldn't add the 1 to the position of the final nul terminator.
Here's the "quick fix" for your current code:
for (int i = 0; i < string1Len; i++) { // Use "<" in place of "<=" or we copy the null terminator
string3[i] = string1[i];
}
for (int i = 0; i < string2Len; i++) { // Start "i" at 0 for valid "string2" index ...
string3[i + string1Len] = string2[i]; // ... and add "string1Len" for the destination index
}
string3[string1Len + string2Len] = '\0'; // Arrays start at ZERO, so don't add 1 for "nul" terminator position
However, there are some other points and possible improvements. Note that the strnlen function returns a size_t type, so you would be better off using that for your indexes. Also, as you know that the i index at the end of the first loop will still be valid for the next character, you can re-use that in the second loop (so long as you have declared it outside the first loop), and you can use a second index for the source string.
Also, as pointed out by chqrlie, you really should check that you have sufficient source data in the argv array.
Here's a version of your program with those additional changes:
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{
if (argc < 3) {
// Error-handling code
return 1;
}
char* string1 = argv[1];
char* string2 = argv[2];
size_t string1Len = strnlen(string1, 50);
size_t string2Len = strnlen(string2, 50);
size_t i, j;
char string3[string1Len + string2Len + 1];
for (i = 0; i < string1Len; i++) {
string3[i] = string1[i];
}
for (j = 0; j < string2Len; j++, i++) {
string3[i] = string2[j];
}
string3[i] = '\0';
printf("%s %zu %zu\n", string3, string1Len, string2Len); // "%zu" for "size_t"
return 0;
}
The problem in your second loop is that i starts beyond the beginning of the second string. However, if all you are trying to do is to write you own custom (max 50 chars) concatenate program, all you need to do is to printf the arguments one after the other and printf can help limit:
#include <stdio.h>
int main(int argc, char *argv[])
{
for (int i = 1; i < argc; ++i) printf("%.50s", argv[i]);
printf("\n");
return 0;
}
There is no need to copy in memory to a VLA and print.
If you need to create a function that concatenates, you better use malloc - as you can't safely return a VLA: (note, the following example will not limit to 50 chars):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* concat(int argc, char* argv[]) {
size_t totalsize = 1;
for (int i = 0; i < argc; ++i) totalsize += strlen(argv[i]);
char* ret = malloc(totalsize);
if (!ret) exit(1);
if (!argc) *ret = 0;
char* dst = ret;
for (int i = 0; i < argc; ++i) {
char* src = argv[i];
while (*dst++ = *src++); /* Copy also the \0 */
--dst;
}
return ret;
}
int main(int argc, char *argv[])
{
char* str = concat(argc - 1, argv + 1); /* Skip the program name */
printf("%s\n", str);
free(str);
return 0;
}
Note that the above examples will concatenate any number of strings.
The index values in both loops are incorrect:
you should stop the first loop when i == string1Len, hence the test should be:
for (int i = 0; i < string1Len; i++)
you should use add string1Len to the index into the destination string so bytes from the second string are appended to those of the first string:
for (int i = 0; i < string2Len; i++) {
string3[string1Len + i] = string2[i];
}
the index for the null terminator is string1Len + string2Len, adding 1 is incorrect as indexing is zero based in C:
string3[string1Len + string2Len] = '\0';
you should test the actual number of arguments provided to the program to avoid undefined behavior if some are missing.
Here is a modified version:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
if (argc < 3) {
fprintf(stderr, "missing arguments\n");
return 1;
}
char *string1 = argv[1];
char *string2 = argv[2];
int string1Len = strnlen(string1, 50);
int string2Len = strnlen(string2, 50);
char string3[string1Len + string2Len + 1];
for (int i = 0; i < string1Len; i++) {
string3[i] = string1[i];
}
for (int i = 0; i < string2Len; i++) {
string3[string1Len + i] = string2[i];
}
string3[string1Len + string2Len] = '\0';
printf("%s %d %d\n", string3, string1Len, string2Len);
return 0;
}

Reverse command-line arguments (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
}
}

Checking for palindrome string in c

I am accepting a string as a command line argument. I want to check whether the inputted string is a palindrome or not and print the result. I have written the following code. But its displaying the result 'not palindrome' for all inputs.
#include<stdio.h>
#include<string.h>
int main(int argc, char argv[20]) {
int i;
int l = strlen(argv);
char str[20];
bzero(str, 20);
for(i=0; i<l; i++)
{
str[i] = argv[i+2];
}
int flag;
int len = strlen(str);
for(i=0; i< len/2; i++)
{
if(str[i] == str[len - (i+2)])
{
flag = 0;
}
else
{
flag = 1;
break;
}
}
if(flag == 0)
printf("Palindrome\n");
else
printf("Not a palindrome\n");
}
You could do it in a K&R-style by having two offset iterators in a for-loop:
#include <stdio.h>
#include <string.h>
#include <assert.h>
int main(int argc, char *argv[]) {
assert(argc != 1);
char *text = argv[1];
int len = strlen(text);
int is_palindrome = 1;
int i, j;
for(i = 0, j = len - 1; i < len / 2; i++, j--) {
if(text[i] != text[j]) {
is_palindrome = 0;
break;
}
}
printf("%s a palindrome.\n", is_palindrome ? "is" : "isn't");
return(0);
}
Changes from original:
Changed shift(len >> 1) to division(len / 2) as tenfour suggested.
Updated based on comments:
int is_palindrome(const char *s)
{
const char *t = s + strlen(s);
while (s<t && *s==*--t) s++;
return s>=t;
}
And since the OP wants a version that's not so heavy on pointers:
int is_palindrome(const char *s)
{
size_t i=0, j = strlen(s);
while (i<j && s[i]==s[--j]) i++;
return i>=j;
}
For reference, here's the original buggy version:
int is_palindrome(const char *s)
{
const char *t = s + strlen(s) - 1;
while (s<t && *s++==*t--);
return s>=t;
}
For one thing, your signature for main is off. It should be int main(int argc, char** argv) or int main(int argc, char * argv[]). You're treating a pointer to a string as if it were a string.
When you've changed that, the string you want should be in argv[1] (since argv[0] is some representation of the program name).
There's a good case for using pointers rather than indexes for this:
int is_palindrome(const char *s) {
const char *end = s + strlen(s);
while (end > s) {
--end;
if (*end != *s) return 0;
++s;
}
return 1;
}
If you like short, confusing code, you can re-write that:
int is_palindrome(const char *s) {
const char *end = s + strlen(s);
while (end > s) if (*(--end) != *(s++)) return 0;
return 1;
}
argv isn't a string, it's an array of strings, one for the program name and then one for each argument (usually space-separated in a command line). So to test if the first argument is a palindrome, you're interested in argv[1].
int main(int argc, char **argv) {
if (argc != 2) {
printf("usage: %s <string>\n", argv[0]); // or something
return 1;
}
if (is_palindrome(argv[1])) {
printf("Palindrome\n");
} else {
printf("Not a Palindrome\n");
}
}
The first loop doesn't make sense.
Copying the string to another doesn't make sense.
Just do it and adjust the index:
#include<stdio.h>
#include<string.h>
int main(int argc, char **argv) {
int i;
char * str = argv[1];
int flag;
int len = strlen(str);
for(i=0; i< (len+1)/2; i++)
{
printf("DEBUG: Comparing %c %c\n",str[i], str[len - (i+1)]);
if(str[i] == str[len - (i+1)])
{
flag = 0;
}
else
{
flag = 1;
break;
}
}
if(flag == 0)
printf("Palindrome\n");
else
printf("Not a palindrome\n");
}
No pointers (except the one use for making a copy of the original string).
#include <stdio.h>
#include <string.h>
int main( int argc, char *argv[] )
{
char *s2;
if ( argc != 2 )
return ( 1 ); // not properly invoked
if ( (s2 = strdup( argv[1] )) == NULL )
return ( 2 ); // failed (not likely)
printf( "\"%s\" %s a palindrome.\n", argv[1], strcmp( argv[1], strrev( s2 ) ) ? "is not" : "is" );
free( s2 );
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