What happened to my strings in both strcpy() and custom function? - c

I have been doing well with the string functions I've been making recently. So then, I made my 3rd string function that is basically like strcpy():
#include <stdio.h>
#include <string.h>
const char *copy_str(const char *str);
int main() {
char name[256];
printf("What's your name? "); scanf("%255s", name);
char result[256] = copy_str(name);
printf("Hello, %s.\n", result);
}
const char *copy_str(const char *str) {
return str;
}
I didn't try using the strcpy() function itself in the function I made, because I'm not really familiar with it. Then I got an error:
copy_str.c:9:10: error: array initializer must be an initializer list or string literal
char result[256] = copy_str(name);
^
I fixed it this way:
int main() {
char name[256];
printf("What's your name? "); scanf("%255s", name);
char result[256];
strcpy(name, result);
printf("Hello, %s.\n", result);
}
But then the output went like this:
What's your name? builderman
Hello, .
No string for some reason. Even if you typed in a different string, it would be the same result.
Q: Why did strcpy() ruin my string? What ways can I improve my function?

I will try to answer your questions in parts.
copy_str.c:9:10: error: array initializer must be an initializer list or string literal
char result[256] = copy_str(name);
the meaning of this error is that in C syntax you cannot initialize an array the way that you did.
you can only initialize an array of chars with either a literal like so:
char name[] = "Hello";
or an initialization list like so:
char name[] = {'H', 'e', 'l', 'l', 'o'};
you can't initialize an array with a pointer to a char (which is the return value of your function)
strcpy doesn't magically copy an entire string to another one, it iterates over the string until it finds a NULL terminator '\0'
so a simple implementation of strcpy can be:
char *StrCpy(char *dest, const char *src)
{
char *returned_str = dest;
while (*src != '\0')
{
*dest = *src;
src++;
dest++;
}
*dest = '\0';
return returned_str;
}
so strcpy iterates over the strings and copies each character from src to dest.
a problem may arise when sending an array of characters that doesn't have a null terminator at the end of the array, which is how a string should be terminated in C.

The function strcpy has the following declaration
char *strcpy(char * restrict s1, const char * restrict s2);
That is the first parameter defines the array where the string pointed to by the second parameter is copied.
However in your program
int main() {
char name[256];
printf("What's your name? "); scanf("%255s", name);
char result[256];
strcpy(name, result);
printf("Hello, %s.\n", result);
}
you are copying the non-initialized character array result into the array name.
You have to write
strcpy( result, name );
instead of
strcpy(name, result);
As for the first program then the function copy_str is redundant. You could just write
char result[256] = name;
However the initializer has the type char * due to the implicit conversion of an array to pointer to its first element. So such initialization of an array is incorrect. You may initialize a character array with a string literal like
char s[] = "Hello";
But you may not use a character pointer to initialize a character array like
char t[] = "Hello";
char s[] = t;
Your function copy_str could look the following way
char * copy_str( char *dsn, const char *src )
{
for ( char *p = dsn; ( *p++ = *src++ ); );
return dsn;
}

Related

cannot append string in C (program stops)

I'm trying to append a string, but whenever it gets to the strcat() function the program exits without printing the string.
I've been running this code from within Visual Studio as well as from its own .exe file and get the same result. Can anybody tell me what I'm doing wrong?
main()
{
char str[100], slash = 'H';
gets(str);
printf("\n\n%s\n\n%i\n\n", str, strlen(str));
strcat(str, slash);
printf("\n%s", str);
}
The function gets is unsafe and is not supported by the C Standard. Instead you standard C function fgets.
The function strcat is declared the following way
char * strcat(char * restrict s1, const char * restrict s2);
That is it expects two arguments of the pointer type char * that point to string literal. However the variable slash is declared as having the type char
char str[100], slash = 'H';
Instead you should write the declaration the following way
char str[100], *slash = "H";
Now the variable slash has the pointer type char * and points to the string literal "H".
Pay attention to that you should guarantee that the array str has a space to accommodate the string literal.
Also to output the returned value of the function strlen you have to use the conversion specifier zu instead of i or d
printf("\n\n%s\n\n%zu\n\n", str, strlen(str));
Also bear in main that according to the C Standard the function main without parameters shall be declared like
int main( void )
Actually if you need to append only one character to a string then it can be done without the function strcat the following way
#include <stdio.h>
#include <string.h>
int main( void )
{
char str[100], slash = 'H';
fgets( str, sizeof( str ), stdin );
size_t n = strcspn( str, "\n" );
if ( n != sizeof( str ) - 1 )
{
str[n] = slash;
str[++n] = '\0';
}
printf( "\n%s\n", str );
}
char * strcat ( char * destination, const char * source ); this is a declaration of strcat(), so the second type should be a pointer to c-string, but you are passing a single character.
#include <stdio.h>
#include <string.h>
int main()
{
char str[100], slash[] = "H";
fgets(str, sizeof(str), stdin);
str[strcspn(str, "\n")] = '\0';
printf("\n\n%s\n\n%i\n\n", str, strlen(str));
strcat(str, slash);
printf("\n%s", str);
return 0;
}
Just convert slash to be c-string instead of a single character.

Function to concatenate two strings in C using strlen but without using strcat

I need to concatenate the strings "abc" and "def" using strlen but without using strcat. Can someone show me what is wrong with my main() function?
#include <stdio.h>
#include <string.h>
void strconcatenate(char *string1, char *string2) {
int i;
int j = strlen(string1);
for (i = 0; string2[i]; i++) {
string1[i+j] = string2[i];
}
string1[i + j]= '\0';
}
int main() {
char string1[3] = "abc";
string1[strlen(string1) - 1] = '\0';
char string2[3] = "def";
string2[strlen(string2) - 1] = '\0';
strconcatenate(string1, string2);
printf("Resultant string = %s\n", string1);
return 0;
}
In main you declared character arrays with three elements
char string1[3] = "abc";
//...
char string2[3] = "def";
These arrays do not contain strings because they do not store the terminating zero character '\0' of the string literals used as initializers. The first array contains three characters { 'a', 'b', 'c' } and the second array contains these three characters { 'd', 'e', 'f' }.
Then you applied the standard string function strlen to these arrays which expects that passed to it arrays contains strings. That is the function calculates the number of characters in a string by counting characters until the terminating zero character is encountered. As the arrays do not contain the terminating zero character '\0' that is as the arrays do not contain strings the calls of strlen invoke undefined behavior.
If you want to append one string to another string then the destination character array shall have enough size to be able to accommodate the second string.
Thus the function main can look the following way
int main( void ) {
char string1[7] = "abc";
char string2[] = "def";
printf( "Resultant string = %s\n", strconcatenate( string1, string2 ) );
return 0;
}
Now the both arrays string1 and string2 contain strings. Moreover the array string1 reserved enough space to accommodate the string stored in the array string2.
The declaration of the function strconcatenate should be similar to the declaration of the standard C function strcat.
char * strconcatenate( char *string1, const char *string2 );
That is the second parameter should have the qualifier const because the passed array is not changed within the function and the function should return the destination array that will contain the concatenated strings.
The function definition will look the following way
char * strconcatenate( char *string1, const char *string2 )
{
for ( char *p = string1 + strlen( string1 ); *p++ = *string2++; );
return string1;
}
There are multiple problems in your code:
[major] char string1[3] = "abc"; defines the destination array with a size of 3 bytes which does not have a enough space for the string "abc" including its null terminator and definitely not long enough to receive the extra characters from string2 at the end. Change this to char string1[7] = "abc";
[major] char string2[3] = "def"; defines the source array with a size of 3 bytes which does not have a enough space for the string "def" including its null terminator, hence will not be null terminated.
[major] string1[strlen(string1) - 1] = '\0'; overwrites the last character of abc, this not necessary.
[major] same remark for string2[strlen(string2) - 1] = '\0';
[minor] string2 should be defined as const char * in void strconcatenate(char *string1, char *string2)
[minor] i and j should be defined with type size_t
[minor] for compatibility with the standard function strcat, strconcatenate should have a return type of char * and return the pointer to the destination array. Yet, As commented by Jonathan Leffler, a more useful design for the return value is to return a pointer to the null at the end of the concatenated string. You already know where the start of the string is; that isn't very interesting information. But knowing where the end of the string is after concatenation — that is useful information which only the concatenate function is privy to. –
Here is a modified version:
#include <stdio.h>
#include <string.h>
char *strconcatenate(char *string1, const char *string2) {
char *p = string1 + strlen(string1);
while ((*p = *string1) != '\0') {
string1++;
p++;
}
return string1; /* strcat semantics */
//return p; /* alternative semantics */
}
int main() {
char string1[7] = "abc";
char string2[] = "def";
strconcatenate(string1, string2);
printf("Resultant string = %s\n", string1);
return 0;
}
Since string1 and string2 has 3 characters so you need to declare it with 4 bytes('\0') and also when you need not to subtract 1 from strlen because it points to '\0' character.
Below is the change to the code.
int main()
{
char string1[4] = "abc";
string1[strlen(string1)] = '\0';
char string2[4] = "def";
string2[strlen(string2)] = '\0';
strconcatenate(string1,string2);
printf("Resultant string = %s\n",string1);
return 0;
}

C -swap 2 chars recursively with only one pointer

I need to write a function:
void swap (char * s1, char * s2);
The function will replace the contents of both strings 1s and 2s.
Constraints:
In the function, there is no use of [] anywhere, but performance by working with pointers, in addition, trips must be made with the voters, meaning that they will actually move to another cell as needed, and will not remain in the same location all the time.
• No loops in the function, that is, work in recursion.
I did the function with pointer to pointer str** but must change it to only one pointer str and recursively. How can I change it?
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *str1="abc",*str2="xyz",*pRev;
swap(&str1, &str2);
printf("str1 is %s, str2 is %s", str1, str2);
getchar();
return 0;
}
//need *str NOT **str
void swap(char **str1, char **str2);
char * RevWords (char * str, int size);
void swap(char **str1, char **str2)
{
char *temp = *str1_ptr;
*str1_ptr = *str2_ptr;
*str2_ptr = temp;
}
after swap method:
str2="abc", str1="xyz"
Well this is clearly not an ideal solution but gives you something to work with.
However this will only work (as mentioned above) when you have the same length of strings (or yes, you'll have to allocate memory + you'd need to know the length of your strings). But otherwise I think this may answer your question.
This is working with recursion and depends on the fact that both strings are the same length and containing a zero character at the end of each one.
#include <stdio.h>
#include <stdlib.h>
void swap(char* str1, char* str2)
{
// if both of them are zero characters then stop
if (*str1 == '\0' && *str2 == '\0')
return;
// else swap the contents of the pointers
else
{
char tmp = *str1;
*str1 = *str2;
*str2 = tmp;
// advance both pointer and swap them too if thye are not '\0'
swap(++str1, ++str2);
}
}
int main()
{
char str1[] = "abc\0\0\0"; // padded with zeros to be the same length as str2
char str2[] = "xyz123"; // the last '\0' is automatically added
swap(str1, str2);
printf("str1 is %s, str2 is %s", str1, str2);
getchar();
return 0;
}

initialization makes pointer from integer without a cast in C warning

On const char * const str = ch; there is a warning:initialization makes pointer from integer without a cast.
If I change it to const char * const str = (char*)ch the warning will be cast to pointer from integer of different size.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv){
FILE *file1;
char ch;
char array[100];
file1 = fopen("list.txt","r");
while((ch=fgetc(file1))!=EOF)
{
const char * const str = (char*)ch;
const char * const delim = "\n";
char * const dupstr = strdup(str);
char *saveptr = NULL;
char *substr = NULL;
int count = 0;
printf("original string is %s",dupstr);
substr = strtok_r(dupstr, delim, &saveptr);
do{
printf("#%d filename is %s\n", count++, substr);
substr = strtok_r(NULL, delim, &saveptr);
}
while(substr);
free (dupstr);
return 0;
}
fclose(file1);
return 0;
}
ch=fgetc(file1))!=EOF is incorrect because ch is a char, but EOF is an int. This is the very reason why fgetc and similar functions return an int. Easiest way to fix the current code is probably to use a temporary int, then copy that to a char inside the loop.
const char * const str = (char*)ch;. Casting from a character to a pointer doesn't make any sense. This is the reason for the warning. If you want to create a temporary string consisting of one character, you should do something like char str[2] = {ch, '\0'}. That way you don't have to use strdup either.
ch is a char (an integral type) and you try to convert it to a pointer type char * (a type that can store an address). These two types are of very different nature, and it is forbidden by the standard to do such. At least convert the address of ch : (char *)&ch.
Beware this will not save your code as you are trying to use a char as a C-string. Again these are of different kind. A char is just something that let you store the code value of a character. A C-string is a sequence of characters terminated by a NUL one.
Suggestions (we don't really know what you try to achieve) : use an array of chars, read a full line from your opened file with fgets, etc.

How to add a char/int to an char array in C?

How can I add '.' to the char Array := "Hello World" in C, so I get a char Array: "Hello World." The Question seems simple but I'm struggling.
Tried the following:
char str[1024];
char tmp = '.';
strcat(str, tmp);
But it does not work. It shows me the error: "passing argument 2 of ‘strcat’ makes pointer from integer without a cast"
I know that in C a char can be cast as int aswell. Do I have to convert the tmp to an char array aswell or is there a better solution?
strcat has the declaration:
char *strcat(char *dest, const char *src)
It expects 2 strings. While this compiles:
char str[1024] = "Hello World";
char tmp = '.';
strcat(str, tmp);
It will cause bad memory issues because strcat is looking for a null terminated cstring. You can do this:
char str[1024] = "Hello World";
char tmp[2] = ".";
strcat(str, tmp);
Live example.
If you really want to append a char you will need to make your own function. Something like this:
void append(char* s, char c) {
int len = strlen(s);
s[len] = c;
s[len+1] = '\0';
}
append(str, tmp)
Of course you may also want to check your string size etc to make it memory safe.
The error is due the fact that you are passing a wrong to strcat(). Look at strcat()'s prototype:
char *strcat(char *dest, const char *src);
But you pass char as the second argument, which is obviously wrong.
Use snprintf() instead.
char str[1024] = "Hello World";
char tmp = '.';
size_t len = strlen(str);
snprintf(str + len, sizeof str - len, "%c", tmp);
As commented by OP:
That was just a example with Hello World to describe the Problem. It
must be empty as first in my real program. Program will fill it later.
The problem just contains to add a char/int to an char Array
In that case, snprintf() can handle it easily to "append" integer types to a char buffer too. The advantage of snprintf() is that it's more flexible to concatenate various types of data into a char buffer.
For example to concatenate a string, char and an int:
char str[1024];
ch tmp = '.';
int i = 5;
// Fill str here
snprintf(str + len, sizeof str - len, "%c%d", str, tmp, i);
In C/C++ a string is an array of char terminated with a NULL byte ('\0');
Your string str has not been initialized.
You must concatenate strings and you are trying to concatenate a single char (without the null byte so it's not a string) to a string.
The code should look like this:
char str[1024] = "Hello World"; //this will add all characters and a NULL byte to the array
char tmp[2] = "."; //this is a string with the dot
strcat(str, tmp); //here you concatenate the two strings
Note that you can assign a string literal to an array only during its declaration.
For example the following code is not permitted:
char str[1024];
str = "Hello World"; //FORBIDDEN
and should be replaced with
char str[1024];
strcpy(str, "Hello World"); //here you copy "Hello World" inside the src array
I think you've forgotten initialize your string "str": You need initialize the string before using strcat. And also you need that tmp were a string, not a single char. Try change this:
char str[1024]; // Only declares size
char tmp = '.';
for
char str[1024] = "Hello World"; //Now you have "Hello World" in str
char tmp[2] = ".";
Suggest replacing this:
char str[1024];
char tmp = '.';
strcat(str, tmp);
with this:
char str[1024] = {'\0'}; // set array to initial all NUL bytes
char tmp[] = "."; // create a string for the call to strcat()
strcat(str, tmp); //

Resources