Pointers and array increment problems - c

I am learning Pointers for the first time from c K&R there was a question about creating your own Strcat function with the help of pointers and stumbled upon few things which i could not understand . I made use of printf statements to understand a part of what was going on but i am still couldn't grasp it completely .
Code:-
void *Strcat(char *a , char *b)
{
printf("*a =%c\n" , *a ) ;
while ( *a != '\0' )
++a ;
printf("*a =%c\n" , *a ) ;
*a++ = *b++ ;
printf("a =%s\n" , a ) ;
printf("*b =%c\n" , *b ) ;
while( *a++ = *b++ ) ;
}
int main(int argc , char *argv[])
{
char s[] = "Hello" ;
char t[] = "World" ;
Strcat( s, t) ;
printf("s=%s\n" , s) ;
printf("t=%s\n",t) ;
return 0 ;
}
PS- I realized that i created a pointer to null function , initially it was pointer to char to imitate the original library function but during testing i changed it to void to remove complexities . Sorry for that
Output :-
*a =H
*a =
a =World
*b =o
s=HelloWorld
t=orld
My shortcomings :-
1. a=World // 3rd output Line
I understand '%s' reads untill '\0' character . By using *a++ = *b++ I was expecting that i was just equating the value present at that memory adress(of a) with one at b but i guess there's more to it since the output is "World"
2. t=orld
I guess i somehow changed the base adress of t as well but i thought that by passing adress of the array i would just be changing the values at the given memory address but i somehow changed its base address as well
3. If any one could explain my concoction that Strcat has become
I want to thank everyone who went through my entire long post even if you couldn't help me , it means a lot to me . So thanx for helping a fellow beginner out!!!

When you create a string as:
char str[] = "World";
The length of str will be 6 (its characters plus the null terminating character).
If you try to add values after it using pointers, what you're doing is accessing invalid memory, because that memory doesn't belong to your string; because you created your string with 6 bytes, it can put it anywhere in memory, hence, the other memory might belong to something important that you may not change.
What you could've done is created your first string with a specified length:
char s[11] = "Hello";
Because HelloWorld\0 is 11 bytes wide, you can create an array of chars with 11 bytes.
Now you may be wondering: "What if I wanted to work with generic length strings?"
Then, you'd have to use dynamic memory for that.
EDIT:
To answer your question:
I understand '%s' reads untill '\0' character . By using *a++ = *b++ I was expecting that i was just equating the value present at that memory adress(of a) with one at b but i guess there's more to it since the output is "World"
The output is just World because once you tried to change it, it didn't let you, because its memory was invalid (as explained earlier). Because of that, the string remained the same as it started.

This has nothing to do with pointers directly; man strcat:
The strcat() function appends the src string to the dest string,
overwriting the terminating null byte ('\0') at the end of dest, and then adds a terminating null byte.
The strings may not overlap, and the dest string must have enough
space for the result.
If dest is not large enough, program
behavior is unpredictable; buffer overruns are a favorite avenue for
attacking secure programs.
while ( *a != '\0' )
++a ;
This fast-forwards the pointer a to the end of the string which is in this case also the end of the allocated memory. Any further increment and access will give UB. But this is not strcat's problem: it is the caller's responsability.
With an additional string:
char t[] = "World" ;
char x[] = "uuuuuuuuuu" ;
char s[] = "Hello" ;
you see the confusion:
*a =H
*a =
a =uuuuuuuuuu
*b =o
s=HelloWorld
t=World
x=orld

Related

Deleting an element in the middle of array?

I was trying to get an element deleted from the middle of array and then shiffting the whole content, and I had a few difficulties because my test array wasn't "right". I fixed the problem by filling the array with a string using strcpy. The commented part above strcpy is the method I used before(which didn't work). Could somebody explain me maybe why isn't it working?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char *array;
int i=5;
array = (char*)calloc(1024, sizeof(char));
if(array == NULL){
printf("Out of memory\n");
return 0;
}
//array = "Just some test string";
strcpy(array, "Just some test string");
printf("%s\n", array);
memmove(array+i+1, array+i, strlen(array)-i);
array[i] = ',';
printf("%s\n", array);
memmove(array+i, array+i+1, strlen(array)-i);
printf("%s\n", array);
free(array);
return 0;
}
The printf is normally working on the commented part, but the memmove() makes my programm crash!
If you have this:
array = "Just some test string";
then
1) You have memory leak due to overwriting the calloc'ed pointer.
2) You are attempting to modify a string literal. That's probably why it crashes. Modifying a string literal is undefined behaviour. They are typically stored in read-only memory. Since strcpy() makes a copy of the string literal, it works as intended and this method fails.
In these statements
memmove(array+i+1, array+i, strlen(array)-i);
array[i] = ',';
there is an attempt to insert character ',' at the position 5 because variable i was initialized with 5.
So the part of the string including the terminating zero has to be shifted right starting with this position. The length of the part is
strlen( array ) - i + 1
because the terminating zero is also must be moved.
So these statements will look like
memmove( array + i + 1, array + i, strlen( array ) - i + 1 );
array[i] = ',';
Then in these statements
memmove( array + i, array + i + 1, strlen( array ) - i );
This statement is correct. Expression strlen( array ) - i is calculated like
( strlen( array ) + 1 ) - ( i + 1 )
As for this statement
array = "Just some test string";
then pointer array points to a string literal and though string literals in C have types of non-constant character arrays nevertheless they are immutable.
Any attempt to modify a string literal results in undefined behaviour of the program.
Also if before this statement you also initialized this pointer with the result of a call to calloc then there will be a memory leak because the pointer is reassigned and the address of the allocated memory is lost.
I tried to do something like this.
I solved it by having:
*(array+strlen(string)+1)=0;
Null terminating the string, but if the subsequent printf() is working correctly this won't help.
Otherwise see:
http://www.java-samples.com/showtutorial.php?tutorialid=591

strcat (s1, s2) continues to apparent to my temp variable array

Newbie to programming (school) and I'm a little confused on what/why this is happening.
I have a loop that is iterating over an array of elements, for each element I am taking the integer of the array, converting it to a char using the function getelementsymbol, and using strcat to append to my temp array. The problem I am having is that the elements of my temp array contain the residual of the element proceeding it. This is the snippet of my code. The output I receive is this:
word1
word1word2
word1word2word3
char* elementsBuildWord(const int symbols[], int nbSymbols){
/* ROLE takes a list of elements' atomic numbers and allocate a new string made
of the symbols of each of these elements
PARAMETERS symbols an array of nbSymbols int which each represent the atomic number
of an element
nbSymbols symbols array's size
RETURN VALUE NULL if the array is of size <= 0
or if one of the symbols is not found by our getElementSymbol function
other the address of a newly allocated string representing the concatenation
of the names of all symbols
*/
char s1[MAX_GENERATED_WORD_LENGTH];
int y;
char *s2;
size_t i;
for (i = 0; i < nbSymbols; i++){
y = symbols[i];
s2 = getElementSymbol(y);
strcat(s1, s2);
}
printf("%s ", s1);
}
Firstly, your s1 is not initialized. strcat function append a new string to an existing string. This means that your s1 has to be a string from the very beginning. An uninitialized char array is not a string. A good idea would be to declare your s1 as
char s1[MAX_GENERATED_WORD_LENGTH] = { 0 };
or at least do
s1[0] = '\0';
before starting your cycle.
Secondly, your getElementSymbol function returns a char * pointer. Where does that pointer point to? Who manages the memory it points to? This is non-obvious from your code. It is possible that the function returns an invalid pointer (like a pointer to a local buffer), which is why might see various anomalies. There's no way to say without seeing how it is implemented.
strcat is supposed to append to a string. use strcpy if you want to overwrite the existing string. You could also use s1[0] = '\0'; before strcat to "blank" the string if you really want to, but looks like you really want strcpy.
From the snippet above it's not even clear why you need s1 - you could just print s2...

storing value in reverse?

I wrote the function to concatenate two strings using pointers. Like strcat(s,t), so at the end of s, t will be added..
int main ()
{
char b[] = "Hello";
char b1[] = "world";
string_cat(b,b1);
printf("Concatenated string is %s\n",b);
return 0;
}
int string_cat(char *s, char *d)
{
while(*++s != '\0')
;
*s++ = ' ';
while((*s++ = *d++)!='\0'); // Concatenation
printf("S is %c\n",s[-2]); // Just to see the values
}
Concatenation works fine, but when I want to see the way elements are stored, all the elements are stored in negative direction, what I mean is s[-2] equals to 'd', s[-3] equals 'l' .. Is this the way they are stored?
First up b is too small to hold the concatenated string. It has only enough space to hold Hello\0 so what you are doing is undefined. Second, look at this line:
while((*s++ = *d++)!='\0');
^^^
You're advancing s because you're incrementing it. Each time you increment it you should imagine it points one element forward. When you get to the end, s isn't what it started out to be. So s[-2] is actually farther down the line compared to the original s (b in your case).
EDIT
so, how to declare it, so that it dynamically adjusts to new size?
Making it adjust to the right size it tough, if possible. What you can do:
Declare it like so: char b[LENGTH] = "Hello";
Pass another parameter to string_cat specifying the size
After multiple iterations you will eventually end up with something like strncpy / memcpy.
Its not stored in negative direction but rather, because you are incrementing the pointer (*s++ in the while loop while((*s++ = *d++)!='\0');)while concatenating , so at the end s points to the end of the string.
You may want to save a copy of the pointer to ensure that you don't loose the beginning of the string (if you need) inside string_cat
Your code has other potential problems which would lead to stack buffer overrun.
char b[] = "Hello";
is a fixed size buffer. Concatenating b1 with b would eventually lead to buffer overrun causing a UB and might eventually crash.

In C why does my pointer argument change when I modify its contents?

I have this custom string copy function and I've noticed that the *dest argument changes upon dereferencing it and modifying its contents:
char *copyArray(char *dest, char *src)
{
char *a = dest;
while (*dest++ = *src++)
;
char *b = dest;
if ( (a-b) != 0)
printf("Dest pointer has changed\n");
return dest;
}
And if you consider the following code:
int main()
{
char name [] = "Hello, there!";
char *new = copyArray(name, "bye");
printf("New is '%s', name is '%s'\n", new, name);
return 0;
}
I get the following output:
Dest pointer has changed
New is 'o, there!', name is 'bye'
Why does this happen?
My intent was for *new to point to the same location name[] points to, but obviously as the address changed, it points to a different place.
I feel that what's happened is that once the copying ended, C moved the original contents of the destination string minus the number of characters changed (4 for "bye") to a new address and assigned that to *dest.
Is this what's really happening? And could somebody please explain to me why?
This is not really work related, I'm just trying to understand better how pointers behave.
Thank you very much for your replies!
The problem occurs here
while (*dest++ = *src++)
;
which in plain english means copy the thing pointed to by src into the thing pointed to by dest, and after that increment both src and dest (that is, advance both pointers to point to the next thing).
Use a copy of the pointer if you want to avoid changing it - eg the a variable you already created, and return that one.
The argument dest is being incremented (in the while condition) four times (as "bye" is 4 characters including the null which will be assigned on the final iteration of the while) inside the function copyArray() and its value is then returned so new points to name + 4.
To have new point to the beginning of name return a from copyArray().

C - expanding the contents of a string

I am writing a function which expands the string, str1 and stores it as str2. By expansion, I mean if str1 has "a-d", it should be stored in str2 as "abcd". I have written the following code. I get a debug error that stack around the variable str1 is corrupted.
Can someone please point out what's going wrong?
Thanks.
#include <stdio.h>
void expand(char s1[], char s2[]);
int main() {
char s1[] = "Talha-z";
char s2[] = "";
expand(s1, s2);
printf(s2);
}
void expand(char s1[], char s2[]) {
int i = 0;
int j= 0;
int k, c_next;
while ( s1[i] != '\0') {
switch (s1[i]) {
case ('-') :
c_next = s1[i+1];
for ( k = 1; k < c_next; k++) {
s2[j] = s1[i] + k;
j++;
}
break;
}
i++;
j++;
}
s2[j] = '\0';
}
You are not allocating sufficient memory for your target string (s2). But you are attempting to write to it, which means you will be writing into memory that you don't own, causing the corruption.
You will need to use dynamic allocation for s2 (i.e. by using malloc), but you will first need to calculate how much memory you need.
char s2[] = "";
This is equivalent to writing
char s2[1] = { '\0' };
It cannot hold more than a single character (or none at all, if the NUL terminator is required).
The problem is that when you initialize s2, you give it enough room for 1 character (i.e. the null terminating '\0'). Thus when you write into s2:
s2[j] = ...
there are no guarantees about what memory you're writing into.
To allocate memory for s2 dynamically, you need to use malloc. In other words, you need to figure out how much memory is required (i.e. by finding the length of the expanded string) and then give s2 that much memory, and finally fill it in via the procedure you have written.
The string s2 at present is on the stack for local variables for main() and is allocated only one byte for one character. When you call the function, it gets passed stack addresses for s1 and s2. The code is over-writing whatever is next to s2 on the stack of function main(). Hence, the error. Please use dynamic memory allocation as already suggested by Mr. Oli above.
Hope my explanation helps you.

Resources