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;
}
Related
Been trying to remove the first element from a double pointer char array but i keep getting errors.
The input into the argv is from the keyboard using:
argv is defined in main as
int main(int argc, char **argv)
if(!fgets(*argv, 64, stdin))
return 0;
for (int i = 0; i < argc; i++)
{
j = 0;
while(j < strlen(*argv) - 1)
{
if(j == 0)
strcpy(argv + j, argv + j + 1);
j++;
}
}
Error:
warning: passing argument 2 of ‘strcpy’ from incompatible pointer type [-Wincompatible-pointer-types]
22 | { if(j == 0) strcpy(argv + j, argv + j + 1);
| ~~~~~~~~~^~~
| |
| char **
Your code has many compile issues, first you need to define variable j and also using correct braces as follow:
#include <string.h>
#include <stdio.h>
int main(int argc, char **argv) {
if(!fgets(*argv, 64, stdin))
return 0;
for (int i = 0; i < argc; i++)
{
int j = 0;
while(j < strlen(*argv) - 1)
{
if(j == 0)
strcpy(argv + j, argv + j + 1);
j++;
}
}
}
After that, I am strongly against using argv for reading a string because you don't know anything about its size in memory. Also, when you are using the strcpy you must pay attention to the sizes, the destination string should have at least the size of the source.
strlen only works on strings which means char * so using it on char ** is meaningless. The following code copies each string into the left item which I think very similar to what you want to do but please note that string size is very important and strcpy can cause issue.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
const int LEN = 255;
int main(int argc, char **argv) {
int n = 3;
// allocate memory for storing strings
char **strings = malloc(n * sizeof(char *));
// reading strings from user
// and store them
for (int i = 0; i < n; i++) {
strings[i] = malloc(LEN * sizeof(char));
// reads in at most one less than size characters from stream and stores them into the buffer pointed to by s
fgets(strings[i], LEN, stdin);
}
for (int i = 0; i < n - 1; i++) {
// here we consider all the strings has the max size as LEN
// so this copy does not cause error.
strcpy(strings[i], strings[i + 1]);
}
free(strings[n - 1]);
for (int i = 0; i < n - 1; i++) {
printf("[%d] %s", i, strings[i]);
}
}
Also, you can use the non-dynamic way as follows:
#include <string.h>
#include <stdio.h>
#define LEN 255
#define N 3
int main(int argc, char **argv) {
char strings[N][LEN];
// reading strings from user
// and store them
for (int i = 0; i < N; i++) {
// reads in at most one less than size characters from stream and stores them into the buffer pointed to by s
fgets(strings[i], LEN, stdin);
}
for (int i = 0; i < N - 1; i++) {
// here we consider all the strings has the max size as LEN
// so this copy does not cause error.
strcpy(strings[i], strings[i + 1]);
}
for (int i = 0; i < N - 1; i++) {
printf("[%d] %s", i, strings[i]);
}
}
Both programs have the following behavior:
Parham
Ali
Hassan
[0] Ali
[1] Hassan
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;
}
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;
}
How can I split a const char * string in the fastest possible way.
char *inputStr="abcde";
char buff[500];
I would like to have in buffer the following formatted string, format of which must be:
IN('a','ab','abc','abcd','abcde')
I'm learning C and new to the language. I have no clue where to start on this splitting problem.
I don't think you can do this particularly "fast", it seems like it's quite heavily limited since it needs to iterate over the source string many times.
I'd do something like:
void permute(char *out, const char *in)
{
const size_t in_len = strlen(in);
char *put;
strcpy(out, "IN(");
put = out + 3;
for(i = 1; i < in_len; ++i)
{
if(i > 1)
*put++ = ',';
*put++ = '\'';
memcpy(put, in, i);
put += i;
*put++ = '\'';
}
*put++ = ')';
*put++ = '\0';
}
Note that this doesn't protect against buffer overrun in the output.
You could use strcpy, strcat/strncat and a simple loop:
#include <stdio.h>
#include <string.h>
int main(void) {
char* inputStr = "abcde";
char buff[500];
// start the formatted string:
strcpy(buff,"IN(");
int i, len = strlen(inputStr);
for (i = 0; i < len; ++i) {
strcat(buff, "'");
strncat(buff, inputStr, i + 1);
strcat(buff, "'");
// if it is not last token:
if (i != len - 1)
strcat(buff, ",");
}
// end the formatted string:
strcat(buff,")");
printf("%s", buff);
return 0;
}
outputs the desired IN('a','ab','abc','abcd','abcde')
To give you a start, consider the following code:
char buffer[64];
const char str[] = "abcde";
for (size_t i = 1; i <= strlen(str); ++i)
{
strncpy(buffer, str, i);
buffer[i] = '\0'; /* Make sure string is terminated */
printf("i = %lu, buffer = \"%s\"\n", i, buffer);
}
The above code should print
i = 1, buffer = "a"
i = 2, buffer = "ab"
i = 3, buffer = "abc"
i = 4, buffer = "abcd"
i = 5, buffer = "abcde"
If you are looking for something like this in C++:-
#include <iostream>
#include <string.h>
using namespace std;
int main() {
const char *inputStr = "abcde"; //const to remove warning of deprecated conversion
char buff[500];
int count = 0;
for (int i = 0; i < (int) strlen(inputStr); i++) { //cast it to int to remove
// warning of comparison between signed and unsigned
for (int j = 0; j <= i; j++) {
buff[count++] = inputStr[j];
}
buff[count++] = ',';
}
buff[--count] = '\0';
cout << buff;
return 0;
}
Output - a,ab,abc,abcd,abcde
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. ;)