initialization makes pointer from integer without a cast in C warning - c

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.

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.

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

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;
}

Segmentation fault on strcat

I have recently begun working on learning the C language and have repeatedly run into an error in which calling the strcat function from the <string.h> module results in a segmentation fault. I've searched for the answers online, including on this stackoverflow post, without success. I thought this community might have a more personal insight into the problem, as the general solutions don't seem to be working. Might be user error, might be a personal issue with the code. Take a look.
#include <stdio.h>
#include <string.h>
char * deblank(const char str[]){
char *new[strlen(str)];
char *buffer = malloc(strlen(new)+1);
for (int i=0; i<strlen(*str); i++){
if(buffer!=NULL){
if(str[i]!=" "){
strcat(new,str[i]); //Segmentation fault
}
}
}
free(buffer);
return new;
}
int main(void){
char str[] = "This has spaces in it.";
char new[strlen(str)];
*new = deblank(str);
puts(new);
}
I've placed a comment on the line I've traced the segmentation fault back to. The following is some Java to make some sense out of this C code.
public class deblank {
public static void main(String[]args){
String str = "This has space in it.";
System.out.println(removeBlanks(str));
}
public static String removeBlanks(String str){
String updated = "";
for(int i=0; i<str.length(); i++){
if(str.charAt(i)!=' '){
updated+=str.charAt(i);
}
}
return updated;
}
}
Any insights into this error will be much appreciated. Please point out typos as well... I've been known to make them. Thanks.
OK, let's do this.
#include <stdio.h>
#include <string.h>
char * deblank(const char str[]){
char *new[strlen(str)];
^ This line creates an array of pointers, not a string.
char *buffer = malloc(strlen(new)+1);
malloc is undeclared. Missing #include <stdlib.h>. Also, you should check for allocation failure here.
strlen(new) is a type error. strlen takes a char * but new is (or rather evaluates to) a char **.
for (int i=0; i<strlen(*str); i++){
strlen(*str) is a type error. strlen takes a char * but *str is a char (i.e. a single character).
i<strlen(...) is questionable. strlen returns size_t (an unsigned type) whereas i is an int (signed, and possibly too small).
Calling strlen in a loop is inefficient because it has to walk the whole string to find the end.
if(buffer!=NULL){
This is a weird place to check for allocation failure. Also, you don't use buffer anywhere, so why create/check it at all?
if(str[i]!=" "){
str[i]!=" " is a type error. str[i] is a char whereas " " is (or rather evaluates to) a char *.
strcat(new,str[i]); //Segmentation fault
This is a type error. strcat takes two strings (char *), but new is a char ** and str[i] is a char. Also, the first argument to strcat must be a valid string but new is uninitialized.
}
}
}
free(buffer);
return new;
new is a local array in this function. You're returning the address of its first element, which makes no sense: As soon as the function returns, all of its local variables are gone. You're returning an invalid pointer here.
Also, this is a type error: deblank is declared to return a char * but actually returns a char **.
}
int main(void){
char str[] = "This has spaces in it.";
char new[strlen(str)];
*new = deblank(str);
This is a type error: *new is a char but deblank returns a char *.
puts(new);
puts takes a string, but new is essentially garbage at this point.
}
You can't use strcat like you did, it is intended to catenate a C-string at the end of another given one. str[i] is a char not a C-string (remember that a C-string is a contiguous sequence of chars the last being the NUL byte).
You also cannot compare strings with standard comparison operators, if you really need to compare strings then there is a strcmp function for it. But you can compare chars with standard operators as char is just a kind of integer type.
This should do the trick:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * deblank(const char str[]) {
char *buffer = malloc(strlen(str)+1); // allocate space to contains as much char as in str, included ending NUL byte
for (int i=0, j=0; i<strlen(str)+1; i++) { // for every char in str, included the ending NUL byte
if (str[i]!=' ') { // if not blank
buffer[j++] = str[i]; // copy
}
}
return buffer; // return a newly constructed C-string
}
int main(void){
char str[] = "This has spaces in it.";
char *new = deblank(str);
puts(new);
free(new); // release the allocated memory
}
So, not sure whether this helps you, but a C code doing the same as your Java code would look like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char *removeBlanks(const char *str)
{
char *result = malloc(strlen(str) + 1);
if (!result) exit(1);
const char *r = str;
char *w = result;
while (*r)
{
// copy each character except when it's a blank
if (*r != ' ') *w++ = *r;
++r;
}
*w = 0; // terminate the result to be a string (0 byte)
return result;
}
int main(void)
{
const char *str = "This has spaces in it.";
char *new = removeBlanks(str);
puts(new);
free(new);
return 0;
}
I would'nt recommend to name a variable new ... if you ever want to use C++, this is a reserved keyword.
I tried compiling with warnings enabled, here are some you should fix.
You need to include stdlib.h
char *new[strlen(str)] creates an array of char* not of char, so not really a string. Change it to char new[strlen(str)].
To check if str[i] is a space, you compare it to the space character ' ', not a string whose only character is a space " ". So change it to str[i]!=' '
strcat takes a string as the second argument and not a character, like you're giving it with str[i].
Also, what are you using buffer for?
Another mistake, is that you probably assumed that uninitialized arrays take zero values. The new array has random values, not zero/null. strcat concatenates two strings, so it would try to put the string in its second argument at the end of the first argument new. The "end" of a string is the null character. The program searches new for the first null character it can find, and when it finds this null, it starts writing the second argument from there.
But because new is uninitialized, the program might not find a null character in new, and it would keep searching further than the length of new, strlen(str), continuing the search in unallocated memory. That is probably what causes the segmentation fault.
There can be three approaches to the task.
The first one is to update the string "in place". In this case the function can look something like the following way
#include <stdio.h>
#include <ctype.h>
#include <iso646.h>
char * deblank( char s[] )
{
size_t i = 0;
while ( s[i] and not isblank( s[i] ) ) ++i;
if ( s[i] )
{
size_t j = i++;
do
{
if ( not isblank( s[i] ) ) s[j++] = s[i];
} while( s[i++] );
}
return s;
}
int main(void)
{
char s[] = "This has spaces in it.";
puts( s );
puts( deblank( s ) );
return 0;
}
The program output is
This has spaces in it.
Thishasspacesinit.
Another approach is to copy the source string in a destination character array skipping blanks.
In this case the function will have two parameters: the source array and the destination array. And the size of the destination array must be equal to the size of the source array because in general the source array can not have blanks.
#include <stdio.h>
#include <ctype.h>
#include <iso646.h>
char * deblank( char *s1, const char *s2 )
{
char *t = s1;
do
{
if ( not isblank( *s2 ) ) *t++ = *s2;
} while ( *s2++ );
return s1;
}
int main(void)
{
char s1[] = "This has spaces in it.";
char s2[sizeof( s1 )];
puts( s1 );
puts( deblank( s2, s1 ) );
return 0;
}
The program output will be the same as shown above.
Pay attention to this declaration
char s2[sizeof( s1 )];
The size of the destination string in general should be not less than the size of the source string.
And at last the third approach is when inside the function there is created dynamically an array and pointer to the first element of the array is returned from the function.
In this case it is desirable at first to count the number of blanks in the source array that to allocated the destination array with the appropriate size.
To use the functions malloc and free you need to include the following header
#include <stdlib.h>
The function can be implemented as it is shown in the demonstrative program.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <iso646.h>
char * deblank( const char *s )
{
size_t n = 1; /* one byte reserved for the terminating zero character */
for ( const char *t = s; *t; ++t )
{
if ( not isblank( *t ) ) ++n;
}
char *s2 = malloc( n );
if ( s2 != NULL )
{
char *t = s2;
do
{
if ( not isblank( *s ) ) *t++ = *s;
} while ( *s++ );
}
return s2;
}
int main(void)
{
char s1[] = "This has spaces in it.";
char *s2 = deblank( s1 );
puts( s1 );
if ( s2 ) puts( s2 );
free( s2 );
return 0;
}
The program output is the same as for the two previous programs.
As for the standard C function strcat then it cats two strings.
For example
#include <stdio.h>
#include <string.h>
int main(void)
{
char s1[12] = "Hello ";
char *s2 = "World";
puts( strcat( s1, s2 ) );
return 0;
}
The destination array (in this case s1) must have enough space to be able to append a string.
There is another C function strncat in the C Standard that allows to append a single character to a string. For example the above program can be rewritten the following way
#include <stdio.h>
#include <string.h>
int main(void)
{
char s1[12] = "Hello ";
char *s2 = "World";
for ( size_t i = 0; s2[i] != '\0'; i++ )
{
strncat( s1, &s2[i], 1 );
}
puts( s1 );
return 0;
}
But it is not efficient to use such an approach for your original task because each time when the function is called it has to find the terminating zero in the source string that to append a character.
you can try recursively
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void deblank(const char* str, char *dest) {
if (!*str) {*dest = '\0';return;}
// when we encounter a space we skip
if (*str == ' ') {
deblank(str+1, dest);
return;
}
*dest = *str;
deblank(str+1, dest+1);
}
int main(void) {
const char *str = "This has spaces in it.";
char *output = malloc(strlen(str)+1);
deblank(str, output);
puts(output);
free(output);
}

Unable to concatenate two char * pointer value?

All I want to ask a question that if we have two string but these should be in the given code
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
char *getln()
{
char *line = NULL, *tmp = NULL;
size_t size = 0, index = 0;
int ch = EOF;
while (ch) {
ch = getc(stdin);
if (ch == EOF || ch == '\n')
ch = 0;
if (size <= index) {
size += index;
tmp = realloc(line, size);
if (!tmp) {
free(line);
line = NULL;
break;
}
line = tmp;
}
line[index++] = ch;
}
return line;
}
char * combine(char *a,char *buffer){
int stop_var;
int newSize = strlen(a) + strlen(buffer) + 1;
char * newBuffer = (char *)malloc(newSize);
strcpy(newBuffer,a);
strcat(newBuffer,buffer); // or strncat
//printf("Final String %s",newBuffer);
free(a);
a = newBuffer;
return newBuffer;
}
char * fun(char *str)
{
char *str1;
str1=getln();
str=combine(str,str1);
return str;
}
int main(void)
{
char *str;
str= getln();
printf("Initial String %s \n",str);
str=fun(str);
printf("Final String %s \n",str);
}
this code is working fine but string char *str="Fixed value" is fixed is gives runtime error
int main(void)
{
char *str;
str= "Fixed Value";
printf("Initial String %s \n",str);
str=fun(str);
printf("Final String %s \n",str);
}
So, I want to know is it any other way to run the above case in which the string is fixed. I know that "How can we achieve the final value in the same character pointer".
Please Read Note:
There are many Questions related to this question I have tried all the solutions.
I looked the below solutions
concatenate-two-char-arrays-into-single-char-array-using-pointers
concatenate-two-char-arrays
how-to-concatenate-pointer-arrays
concatenate-char-array-in-c
concatenate-two-arrays-using-void-pointer-c
I have searched many more solutions over the internet, but no solutions are fulfilled my condition. These all the solution is using the third variable and showing its value. I want value in the same variable. Even if we are creating any extra variable, its value finally should be assign to char *str.
Please provide me any suggestion to do this in c language only.
The given question is different from my question because in that question they checking the behaviour of the string literals bu for my case I am looking to assigns concatenate value to variable str. And its solution changing pointer to an array but I cannot change because its value is using many functions for my work.
Your function combine() calls free() on its first argument. In your fun() call, which is passed from fun() which points to a string literal in your code.
You cannot call free() on a string literal, that's undefined behaviour. I suggest you to restructure your code so that combine() no longer calls free() on its first argument. Freeing memory should be the callers responsibility.
I would suggest pairs of allocation/deallocation functions:
char * combine_allocate(const char *a, const char *b) {
char* result = malloc(...)
combine ...
return result;
}
void combine_deallocate(char* p) { free(p); }
Having that:
char* a = initial_allocate();
char* b = initial_allocate();
char* c = combine_allocate(a, b);
initial_deallocate(a);
initial_deallocate(b);
// ... use c
combine_deallocate(c)
You may omit (and should) initial_allocate/initial_deallocate for string literals.
It might be a bit too verbose, but object oriented C does nothing else (with nicer function names).

How can I join a char to a constant char*?

I have a function that joins two constant char* and returns the result. What I want to do though is join a char to a constant char* eg
char *command = "nest";
char *halloween = join("hallowee", command[0]); //this gives an error
char *join(const char* s1, const char* s2)
{
char* result = malloc(strlen(s1) + strlen(s2) + 1);
if (result)
{
strcpy(result, s1);
strcat(result, s2);
}
return result;
}
The function you wrote requires two C-strings (i.e. two const char * variables). Here, your second argument is command[0] which is not a pointer (const char *) but a simple 'n' character (const char). The function, however, believes that the value you passed is a pointer and tries to look for the string in memory adress given by the ASCII value of the letter 'n', which causes the trouble.
EDIT: To make it work, you would have to change the join function:
char *join(const char* s1, const char c)
{
int len = strlen(s1);
char* result = malloc(len + 2);
if (result)
{
strcpy(result, s1);
result[len] = c; //add the extra character
result[len+1] = '\0'; //terminate the string
}
return result;
}
If you wish to join a single character, you will have to write a separate function that takes the quantity of characters from s2 to append.
The best is to create a new function that allows adding a single char to a string.
But if you would like to use the join() function as it is for some reason, you can also proceed as follows:
char *command = "nest";
char *buffer = " "; // one space and an implicit trailing '\0'
char *halloween;
*buffer = command[0];
halloween = join("hallowee", buffer);

Resources