Did this program initialize its pointer? - c

This is a simple program to copy a string to a new string from a C programming book (Programming in C, S. Kochan). It runs fine, but there is a pointer that I do not see initialized. I'm struggling with pointers here, but I have imbedded in my coding the C golden commandment: "THOU SHALT NOT USE THY POINTERS THAT ARE NOT INITIALIZED". Here is the code:
#include <stdio.h>
void copyString(char *to, char *from) //I do not see where the 'from' pointer is initilized?
{
for( ; *from != '\0'; ++from, ++to)
{
*to = *from;
}
*to = '\0';
}
int main(void)
{
void copyString (char *to, char *from);
char string1[] = "A string to be copied.";
char string2[50];
copyString(string2, string1);
printf("%s\n", string2);
copyString(string2, "So is this.");
printf("%s\n", string2);
return 0;
}
I was under the impression that all pointers must be initialized in the manner:
*ptr = &variable;
or risk something important in your system being overridden. But I am seeing many programs in my books that are not initializing pointers explicitly, and this makes me very uncomfortable. Please give me some tips about prudent pointer use so I don't destroy my machine, especially anything pertaining to strings. Thanks in advance all!

This confuses you - void copyString (char *to, char *from);. This is just a declaration in main. char *to and char *from in main are not in use so do not worry. The above code is as good as:
#include <stdio.h>
void copyString(char *to, char *from) //I do not see where the 'from' pointer is initilized?
{
for( ; *from != '\0'; ++from, ++to)
{
*to = *from;
}
*to = '\0';
}
int main(void)
{
void copyString (char *, char *);
char string1[] = "A string to be copied.";
char string2[50];
copyString(string2, string1);
printf("%s\n", string2);
copyString(string2, "So is this.");
printf("%s\n", string2);
return 0;
}
//I do not see where the 'from' pointer is initilized?
When you pass arguments like this copyString(string2, string1); - They will be copied into the args on function call of copyString(char *to, char *from). So in the first call:
copyString(string2, string1); - to = string2, and, from = string1
"A string to be copied."
from--^
And in the second call:
to = string2, and, from = "So is this."
"So is this."
from--^
string2 does not cause any problems (even though it was not initialized) since your overwriting its values (which had garbage values before).

to and from are function parameters, when the function is called, they are assigned the value of the arguments:
copyString(string2, string1);
to is assigned the value of stirng2 while from is assigned the value of string1. Note that even though string2 and string1 has type of char arrays, but they "decayed" into a pointer to the first element when passed as function arguments.

You are correct - all pointer must be initialized as you said.
When you're declaring the strings, as an array of characters as below:
char string1[] = "A string to be copied.";
char string2[50];
string1 and string2 are pointer to arrays of strings. So, they are already pointers.
When you used them in the copyString function, you are already using pointers, and the assignent is done implicitly. So:
to = string2 = &string2[0];

Here is a commented version of your code - the "from" variable has been renamed to source, and the printf's for the pointer values should illustrate the source. But suffice to say that the arguments to the copyString function are provided by the two calls to the function in your main program. The compiler generates code which takes the arguments you provide in the calls to the function with instructions to save these arguments onto the function call stack frame. Then when the function is called, these values are referenced in the function.
#include <stdio.h>
//the char pointer dest is provided as an argument
//the char pointer source is provided as an argument
char*
copyString(char *dest, char *source)
{
if(!dest) return dest;
if(!source) return dest;
printf("dest %x, source %x\n", dest, source);
//for each character in source, until *source == '\0'
for( ; *source; )
{
//assign the char at *dest into *source
//then post-increment source, dest
*dest++ = *source++;
}
//ensure the dest string is terminated
*dest = '\0';
return dest;
}
int main(void)
{
char* copyString (char *to, char *source);
char string1[] = "A string to be copied.";
char string2[50];
printf("string2 %x, string1 %x\n", string2, string1);
copyString(string2, string1);
printf("%s\n", string2);
copyString(string2, "So is this.");
printf("%s\n", string2);
return 0;
}
When you run the program, you will see the locations of the source and destination pointers provided,
$ ./copystr
string2 bff0dbe7, string1 bff0dc19
dest bff0dbe7, source bff0dc19
A string to be copied.
dest bff0dbe7, source 80485f0
So is this.

Related

function returns address of local variable [-Wreturn-local-addr] sprintf

i ma new c and i am trying sprintf along with pointers. all i get in console is return buf; as is please help me with this code.
#include <stdio.h>
char* stringa(char* str);
int main()
{
char* ss = "123";
stringa(ss);
return 0;
}
char* stringa( char* str)
{
char buf [100] ;
sprintf(buf,"hello %s", str);
return buf;
}
i tried many other ways too like sprintf_c and my computer shut down for serious. i am learning c.
Maybe this is what you want
#include <stdio.h>
char* stringa(char* dest, char* src)
int main()
{
char buf [100] ;
char* ss = "123";
printf("%s\n", stringa(buf, ss));
return 0;
}
char* stringa(char* dest, char* src)
{
sprintf(dest,"hello %s", src);
return dest;
}
In function 'char* stringa(char* str)' you are not allocating space in the heep for the char array 'buf' you are allocating space on the stack for that variable. (meaning after the function finishes, the variable 'buf' will be wiped away because it will be out of scope) therefore you must ask the compiler to allocate space in memory for this array, I recommend using malloc()
ex:
char* stringa( char* str)
{
char *buf = (char*)malloc(sizeof(char) * 100);
sprintf(buf,"hello %s", str);
return buf;
}
char* stringa( char* str)
{
char buf [100] ;
sprintf(buf,"hello %s", str);
return buf;
}
The problem with this code is that the buf char array is local to the stringa function. When the function returns, the memory occupied by the buf array is not valid anymore (for example, it could be reused later to store the content of other variables, arrays, etc.).
So when the function returns, you are giving the caller a pointer to garbage memory, to invalid data. The C compiler is trying to help you with that warning message; it's telling you: "Sorry, you are trying to pass back to the caller the address of a local variable (i.e. the buf char array) that is not valid anymore when the function terminates."
To fix this problem one option could be to allocate the char array for the output string at the call site, and let the invoked stringa function write into the caller-provided array:
#include <stdio.h>
char* stringa(char* dest, const char* str);
int main()
{
const char* ss = "123";
char buf[100];
stringa(buf, ss);
return 0;
}
/* Write the final message into 'dest'.
* Return the same dest address.
*/
char* stringa(char* dest, const char* str)
{
/* Note: better using a safe string function
* to prevent buffer overflows (e.g. sprintf_s),
* passing the maximum destination array size as well.
*/
sprintf(dest,"hello %s", str);
return dest;
}
Note that I also added some consts in your code to enforce some const-correctness for read-only input strings.

unite two strings by copying one by one the characters of the second at the end of the first

this program it suppose to print Hello World but guess what exited, segmentation fault why is that happening ?
#include <stdio.h>
#include <string.h>
char f(char *a, char *b)
{
int i , m, n;
m = strlen(a);
n = strlen(b);
for (i = 0; i<=n; i++)
{
a[m+i] = b[i];
}
}
int main() {
char*str1 = "hello ";
char*str2 = "world!";
str1=f(str1, str2);
printf("%s", str1);
return 0;
}
You are not allowed to modify string literals. Use arrays with enough elements instead for strings to be modified.
Also assigning the return value of f to str1 is a bad idea because no return statement is executed in the function f and using its return value invokes undefined behavior. The return type should be changed to void if you are not going to return anything.
#include <stdio.h>
#include <string.h>
void f(char *a, char *b)
{
int i , m, n;
m = strlen(a);
n = strlen(b);
for (i = 0; i<=n; i++)
{
a[m+i] = b[i];
}
}
int main() {
char str1[16] = "hello ";
char*str2 = "world!";
f(str1, str2);
printf("%s", str1);
return 0;
}
First of all, this:
char*str1 = "hello ";
is a pointer to constant data, which means that you can't change the string "hello "
This is a constant pointer to variable data:
char str1[] = "hello ";
Which means that str1 always points to the same address in memory, but you can modify the content of that chunk of memory.
However str1 will have a fixed size of 7 characters (don't forget to count \0), so you can't append another string to it.
You could define a size #define SIZE 20 large enough to store both strings and declare
char str1[SIZE] = "hello ";
Or you could declare str1 as a VLA (variable length array) after having declared the string to append:
char*str2 = "world!";
char str1[strlen("hello ")+strlen(str2)+1] = "hello ";
Where the +1 is for \0.
Is it important that you copy characters one by one?
Because if it's not you can just copy one string to another like this.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char str1[] = "hello ";
char str2[] = "world!";
char *result = malloc(strlen(str1) + strlen(str2) + 1);
strcpy(result, str1);
strcat(result, str2);
printf("%s", result);
return 0;
}
First you are not allowed to change a constant string, that is undefined behaviour.
Secondly your f function has no return statement and thus returns random data, making the str1 variable in main point to random memory. Using it then also has undefined behaviour.
To fix it you should allocate new memory and concatenate the string into that
char* f(const char *s1, const char *s2)
{
char *s = malloc(strlen(s1) + strlen(s2) +1);
if (s) {
strcpy(s, s1);
strcat(s, s2);
}
return s;
}
The extra one byte allocated is for the terminating zero.
Both arguments are const as there is no reason to modify them, which allows both arguments to be literal strings.
For starters you may not change string literals (in this case the string literal pointed to by the pointer str1).
char*str1 = "hello ";
char*str2 = "world!";
Any attempt to change a string literal results in undefined behavior.
You need to allocate a character array large enough to store the result string with the appended string literal pointed to by the pointer str2.
Secondly there is already the standard C function strcat that performs the required task. If you have to write such a function yourself then it seems you should not use any string function as for example strlen.
And the return type char of your function does not make a sense. And moreover actually your function returns nothing.
So this assignment
str1=f(str1, str2);
results in undefined behavior.
The function and the program in whole can be written the following way without using standard string functions.
#include <stdio.h>
char * f( char *s1, const char *s2 )
{
char *p = s1;
while ( *p ) ++p;
while ( ( *p++ = *s2++ ) );
return s1;
}
int main(void)
{
char s1[14] = "Hello ";
char *s2 = "World!";
puts( f( s1, s2 ) );
return 0;
}
The program output is
Hello World!
Pay attention to that the second function parameter shall have the qualifier const because the pointed string is not changed within the function. And the function return type should be char * that is the function should return the result string.

Pointers swap values in void function, but won't return swapped values

I'm trying to swap two strings passed in as char pointers.
In debugging, I get the right answers at the end of the called function, but returning the values after the function ends returns the same values as passed in. Here is the code
#include <stdio.h>
int main(int argc, char const *argv[]) {
char *s1, *s2;
s1 = "12345678";
s2 = "87654321";
printf("s1 is %s\n", s1);
printf("s2 is %s\n", s2);
strswap(s1, s2);
printf("s1 is now %s\n", s1);
printf("s2 is now %s\n", s2);
}
and the code for the function itself
#include <stdio.h>
void strswap(char *s1, char *s2){
char *temp;
temp = s1;
printf("temp: %s\n", temp);
s1 = s2;
printf("s1: %s\n", s1);
s2 = temp;
printf("s1: %s\n", s1);
printf("s2: %s\n", s2);
printf("temp: %s\n", temp);
}
I order to swap strings, first of all you can't just use constant string literals since they are immutable. Assigning string literal to char * is considered bad practice unless you properly know what you're trying to achieve. Read this link and this also. You should use statically/dynamically allocated strings.
As other people said, you're passing the character pointers by value, so any changes you make in strswap() would not be reflected in main function. Since some local variables are modified and they get destroyed when control goes out of those functions. You should either pass char ** like in one of the mentioned answers. I would recommend to use statically allocated strings and use strcpy for string copy operations like this:
#include <stdio.h>
#include <string.h>
#define MAX_SIZE 1000
void strswap(char *s1, char *s2){
char tempStr[MAX_SIZE];
strcpy(tempStr, s1);
strcpy(s1, s2);
strcpy(s2, tempStr);
}
int main(int argc, char const *argv[]) {
char aString1[MAX_SIZE] = "Rohan", aString2[MAX_SIZE] = "Rohit";
printf("s1 is %s\n", aString1);
printf("s2 is %s\n", aString2);
strswap(aString1, aString2);
printf("s1 is now %s\n", aString1);
printf("s2 is now %s\n", aString2);
return 0;
}
C uses pass-by-value for function argument passing.
Here, the pointers themselves are passed by value, so any changes made to the pointers (for example, assigning values to them), will not be reflected to the actual arguments in the caller. However, if any change is made to the value stored at the memory location pointed to by the pointers, that would be reflected to the actual arguments used to call the function from the caller.
So, to change a pointer value itself, you need to pass a pointer to the pointer.
You're using string literals to initialize the pointers, you can't swap those strings with the function prototype you showed.
Assuming the string initialization is a mistake, we can do the swap without changing the function's prototype, by copying the actual characters around. This requires that the strings have equal length, otherwise the longer one can't be copied to the space used by the shorter one.
Here's an attempt:
void swap_strings(char *a, char *b)
{
const size_t al = strlen(a);
const size_t bl = strlen(b);
if(al != bl)
return;
for(size_t i = 0; i < al; ++i)
{
const char t = a[i];
a[i] = b[i];
b[i] = t;
}
}
I changed the function's name, I have a vague recollection that you're not supposed to add functions with names beginning with str, that's reserved.
Note: this requires that the strings be writable, so you can't use it on string literals. You have to have proper buffers (or arrays) like this:
char a[] = "foo";
char b[] = "bar";
swap_strings(a, b);
printf("'%s' and '%s'\n", a, b);
This will print 'bar' and 'foo'.

Why is this code getting a segmentation fault?

I am trying to write a function that deletes a char c from a string src, and I am getting a seg fault when I try to run it. Here is the function.
void removeChar(char *src, char c){
int i, j = 0;
int size;
char ch1;
char str1[100];
size = strlen(src);
for (i = 0; i < size; i++){
if (src[i] != c){
ch1 = src[i];
str1[j] = ch1;
j++;
}
}
str1[j] = '\0';
src = str1;
}
And here is the main function where I am calling it.
int main(int argc, char **argv){
char *str = "Hello, world!\0";
printf("%s\n", removeChar(str, 'l'));
}
the return type of this function removeChar(str, 'l') is void not an char array and you are passing this to
printf("%s\n", removeChar(str, 'l'));
so here %s may give you the segmentation fault.
You assigned pointer src by the address of the first element of a local array
src = str1;
that will be destroyed after exiting the function. Moreover variable src is a local variable of the function so any changes of it do not influence the original pointer str.
Take into account that you may not change string literals. Any attempt to change a string literal results in undefined behaviour of the program.
Also the function has return type void and may not be used as an outputed object in function printf.
Type void is an incomplete type. It has no values.
And there is no need to append explicitly terminating zero to a string literal as you did.
"Hello, world!\0"
String literals already have terminating zeroes. So you could write simply
"Hello, world!"
As I already answered this question then you can visit my personal forum where there is a realization of the corresponding valid function.
If to declare correctly the function like
char * removeChar( char *s, char c );
then the main will look the following way
int main(int argc, char **argv)
{
char str[] = "Hello, world!";
printf( "%s\n", removeChar( str, 'l' ) );
}
You can print the string in the function itself! Then it works:
#include <stdio.h>
#include <string.h>
void removeChar(char src[], char c){
int i, j = 0;
int size;
char ch1;
char str1[100];
size = strlen(src);
for (i = 0; i < size; i++) {
if (src[i] != c) {
ch1 = src[i];
str1[j] = ch1;
j++;
}
}
str1[j] = '\0';
src = str1;
printf("%s\n", src);
}
int main(int argc, char **argv) {
char str[] = "Hello, world!";
removeChar(str, 'l');
return 0;
}
You have several bugs:
char *str = "Hello, world!\0";. Setting a non-constant pointer to point at a string literal is always wrong. Instead, declare the variable as const char *str. See this FAQ.
removeChar doesn't return anything so you can't pass it as a parameter to be printed by printf. Your compiler really should have complained here. Chances are that your compiler is misconfigured or you you aren't using it with all warnings enabled.
char str1[100]; You cannot use local variables and then try to pass the contents on to the caller. See this FAQ.
src = str1; doesn't do a thing, since src is only a local copy of the original pointer. With this assignment, you will not change the address of str in main. Which would have been a bug anyway, because of 3) above. You should rewrite your program so that is only uses src and no temporary array.
Not have enough reputation to comment. So, I had to write this on answer:
As Vlad from Moscow pointed out,
`a local array do not exist after the function terminate`
I suggest you obey the same principle as of standard library functions. If you didn't already notice,none string.h function allocate memory for the user. You must allocate before call.
char *str = "Hello, world!\0";
The above code do not guarantee a modifiable memory. The compiler can set them in read only memory. You should use a array instead.

simple strcat implementation with pointers

so I was practicing writing c code with pointers using the K&R. For one problem with strcat function, I couldn't find out what was wrong with my code, which according to Visual Studio, returned the destination string unchanged after the strcat function. Any suggestion is appreciated!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int strcat(char* s, char* t);
int main(void)
{
char *s="hello ", *t="world";
strcat(s,t);
printf("%s",s);
return 0;
}
int strcat(char* s,char* t)
{
int i;
i=strlen(s)+strlen(t);
s=(char*) malloc(i);
while(*s!='\0')
s++;
while('\0'!=(*s++=*t++))
;
return 0;
}
I'm pretty sure that strcat returns a char* in the real implementation (holding the original value of the first string).
strcat is not supposed to alter the first parameter's address, so you shouldn't call malloc.
Point #2 means that you need to declare char *s as char s[20] in main (where 20 is some arbitrary number big enough to hold the whole string).
If you really want to alter the value of the an input parameter you will need to pass the address of the value - so it would need to be strcat(char **s, ...) in the function declaration/definition, and called with strcat(&s, ...) in main.
1) defining string in this way
char *s="hello "
means that you are defined a literal string. a literal string is saved into read only memory so you can not edit it
you have to define your string as a char array in order to be able to edit it
char s[100] = "hello ";
2) when you define your function in this way
int strcat(char* s,char* t)
you can not change the address of s into the function strcat(). So assigning memory with malloc() into the function will not change the s address when leaving the function
3) change your function strcat to
int strcat(char** s,char* t)
{
int i;
char *u, *v;
i=strlen(*s)+strlen(t);
v = *s;
u=(char*) malloc(i+1);
while(*v!='\0')
*u++ = *v++;
while('\0'!=(*u++=*t++));
*s = u;
return 0;
}
and you call it in the main with:
char *s="hello ", *t="world";
strcat(&s,t);
In
strcat(char* s, char* t)
the 's' is send by value. The value of 's' at call time is copied into the stack then strcat() is call. At the return of strcat the modified version is discard from the stack. So the calling value of 's' is never changed (and you create a memory leak).
Beward, in C every memory cell can be change, even parameters or instructions sections; some changes can be very hard to understand.
Since you are trying to do like the real strcat it's said that the first parameter
The string s1 must have sufficient space to hold the result.
so you don't need to use malloc
char *strcat(char* s, const char* t);
int main(void)
{
char s[15] = {0}; //
char *t = "world"; //const char * so you can't change it
strcpy(s, "Hello ");
strcat(s,t);
printf("%s\n",s);
return (0);
}
char *strcat(char* s, const char* t)
{
int i = 0;
while (s[i] != '\0')
i++;
while (*t != '\0')
s[i++] = *t++;
s[i] = '\0'; //useless because already initialized with 0
return (s);
}
#include<stdio.h>
#include<string.h>
#define LIMIT 100
void strcatt(char*,char*);
main()
{
int i=0;
char s[LIMIT];
char t[LIMIT];
strcpy(s,"hello");
strcpy(t,"world");
strcatt(s,t);
printf("%s",s);
getch();
}
void strcatt(char *s,char *t)
{
while(*s!='\0')
{
s++;
}
*s=' ';
++s;
while(*t!='\0')
{
*s=*t;
s++;
t++;
}
*s=*t;
}
Dear user,
you don't have to complicate things that much. The simpliest code for strcat, using pointers:
void strcat(char *s, char *t) {
while(*s++); /*This will point after the '\0' */
--s; /*So we decrement the pointer to point to '\0' */
while(*s++ = *t++); /*This will copy the '\0' from *t also */
}
Although, this won't give you report about the concatenation's success.
Look at this main() part for the rest of the answer:
int main() {
char s[60] = "Hello ";
char *t = "world!";
strcat(s, t);
printf("%s\n", s);
return 0;
}
The s[60] part is very important, because you can't concatenate an another string to it's end if it doesn't have enough space for that.

Resources