memory allocation details using strcat - c++

I'm using following code to print strings.
#include<bits/stdc++.h>
using namespace std;
int main(){
char s[100];
while(1){
char f[10000];
cin>>s;
strcat(f,s);
cout<<f<<endl;
}
return 0;
}
in each iteration a new allocation of f character array is done.
input
a
b
c
d
I expected that the output would be like this:
a
b
c
d
but actual output is:
a
ab
abc
abcd
Why is this happening ? Though I'm declaring a new array in each iteration
so why is this kind of output ??

Because: undefined behavior.
You are not initializing the array. You're only declaring it. Just because you declare
char f[10000];
Does not mean that it's going to be initialized to an empty array, automatically.
So, you get a declared array, containing random data.
At this point, you cannot expect to get any predictable behavior. The results you got would be one plausible outcome. But not the only one.
EDIT: Each time around the loop, the array ends up at the same place on the stack. The first time in, your operating system set up a new page, for the stack, cleared to 0. You strcat()ed your string to it. The next time around the loop, your old data, from the previous iteration, is still there. So, you strcat() more stuff, appending it to the end.

Related

How a pointer to a string works in a function?

I am in learning about pointers and strings and how they work. I have a question which answer may I know already. But, in fact, I want to be sure of it.
Let take the following code for example:
char a[200],*p;
gets(a); // cin.get(a,200);
p=a;
strcpy(p,p+1);
printf("%s",a); // c
cout<<a; // cpp
return 0;
Input : working
Output : orking
So what about this? Why do the array modified without actually modify itself?
char a[200],*p;
gets(a); // cin.get(a,200);
p=a;
p++;
printf("%s",a); // cout<<a;
return 0;
Input : working
Output : working
In this case, why the array did not modify? What has the function strcpy special? And which other functions has this propriety?
Throughout the text, I have referred to the functions of the strings set in the program.
Snippet 1
char a[200],*p;
Defined a block of 200 characters ,a, and a pointer, p, to a block of one or more characters.
gets(a); // cin.get(a,200);
Read some user input into memory block a
p=a;
Points p at block a. p can now be used as a reference to the same thing as a
strcpy(p,p+1);
Copy part of the memory block over itself. NOTE: this invokes undefined behaviour because the to and from buffers in strcpy overlap (See http://en.cppreference.com/w/cpp/string/byte/strcpy). The results may be unusual, ranging from "Looks like it works!" to more fantastic, such as the computer making it rain unicorns.
So, say a is created at memory location 10. Data is read into the block starting at location 10. Then p is set to point at location ten. Then the memory starting at location 11 is copied over the memory starting at location 10. Since a is at 10, printing a prints the altered data. Since p is still pointing at 10, printing p will print the same thing as a.
Snippet 2:
char a[200],*p;
Defined a block of 200 characters ,a, and a pointer, p, to a block of one or more characters.
gets(a); // cin.get(a,200);
Read some user input into memory block a
p=a;
Points p at block a. p can now be used as a reference to the same thing as a
p++;
Moved where p pointed over one slot to the right. Copied nothing. Just changed the address that p points at.
So, say a is created at memory location 10. Data is read into the block starting at location 10. Then p is set to point at location 10. Then p is set to point at memory location 11. The values in memory block a are unchanged. Since a is still at 10, printing a prints the unchanged data. Since p is now pointing at 11, printing p will print the from the second character of a onward.
You are not modifying anything in the second code. Why should it be modified?
Piano points to the first element of a. Then you increment it. So please points to the second element. Then you print a, who wasn't modified.
As for the first one, from strcpy reference :
To avoid overflows, the size of the array pointed by destination shall be long enough to contain the same C string as source(including the terminating null character), and should not overlap in memory with source
I think you have what is called an overlap.
You copy a source to a destination that's overlapping in memory.

accessing array with pointer giving an extra element

Ok a very basic question, but I am stuck at it. I cannot figure out the extra mysterious value at the end of the array. I just tried to traverse the array through its base address, plain and simple. But the garbage value at the end of the array remains constant every time I execute it
g++ complier 64 bit machine.
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
void printarray(int * arr){
while(*(arr)){ cout<<*arr<<" "; arr++; }
cout<<endl;
}
int main(){
int arr[] = { 3,2,4,1,5 };
printarray(arr); // prints 3,2,4,1,5,32765
return 0;
}
EDIT 1: I understand that the while will terminate whenever it comes across a 0 in the array , or if no 0 is found will go insane . But still I would want you guys to look at the following test cases
3,2,0,4,1,5 // outputs 3,2
3,2,4,1,5,7,8,9 // outputs same array correctly
3,2,4,1,5,7,8,9,10 // outputs array+ 1 varying garbage at last
//observations, this method works for even sized arrays not containing
//0, while for odd it emits an additional garbage value.
My question is if the while only breaks at 0 , why does it break at
arrayLength+1 everytime ? Also what's with this even odd length ?
An array is not terminated in any special way. What you are trying to do is not working because while(*arr) relies on a wrong assumption: that there is a 0 element at the end of the array (a sentinel) but you declare the array a {3,2,4,1,5} so there is no end element.
I think your misconcept comes from the fact that you are not getting the point that an int* is just a memory address, whenever you increment it by ++arr you are basically adjusting it by sizeof(int). Nothing more, when you reach the end of the array then the address just points after the array, to whatever value could be there.
You get the extra element(s) because there is nothing about a pointer that tells the compiler how many elements the pointer points to. When you do
while(*(arr)){...}
The while loop will continue running untill *arr == 0. Since you array doesn't contain a 0 it will keep going past the end of the array untill it finds a 0. This is undefined behavior as you are accessing memory you do not own with that pointer.
I think you may be confusing how char arrays(c-strings) work compared to other data types. When you have
char arr[] = "something";
while(*(arr)){...}
This ends at the end of the array as c-strings get a null terminator(0) added to the end of the string automatically. This allows you to do things like the above loop as you know that null terminator will be there and if it is not then that is on the person you created the string.
An array decays into a pointer when passed to a function, and this function knows nothing about the array's length.
That while(*arr) stuff is incorrect. It will stop only when some value this pointer points to is zero. But who said a zero is placed at the end of an array?? When you increment arr, you can easily get out of bounds of your array (the function doesn't know its size!), and then *arr will give you whatever the heck is stored at the memory address arr points to at the moment.
To iterate over an array, pass the array itself and its length. Otherwise this will iterate over and over until the value of *arr will be zero.
Pointers aren't terminated in C++ by any character.
This works on other types like char* only because it's terminated by an \0(0).
An INT-Array u need to count the Elements before you can pass them into something like that, for example here with the ending 5 from your Pointer:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
void printarray(int * arr){
int *saved=arr;
while(*saved!=5)
{
cout<<*saved++<<" ";
}
*saved=0;
cout<<endl;
}
int main(){
int arr[] = { 3, 2, 4, 1, 5 };
printarray(arr); // prints now without ending 5.
return 0;
}
Otherwise, you need to pass the counter of elements.
There is no way C++ could know how many elements your pointer points to.

char* issue in C++ [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
Why this fragment of code does not work? I know that all entered strings have length less than 20 symbols.I do not use std::string because I want to learn how to use char*
#include <map>
#include <stdio.h>
using namespace std;
map <char*,int> cnt;
int main()
{
char ans[20];
int n,mx = 0;
scanf("%d\n",&n);
for ( int i = 1; i <= n; i++){
char str[20];
gets(str);
cnt[str]++;
}
for ( auto i = cnt.begin(); i != cnt.end(); i++ )
puts(i->first);
}
Let's be clear that your code has a lot of undefined behavior. I tried running your code and here is what I saw on my machine. You should tell us what your behavior was though because it's impossible to say what's going on for you otherwise.
First off, here was my program input.
3
hello
world
cat
And the output...
cat
char str[20] is a memory address, and that address is being reused by the compiler. Let's say that memory address is 0xABCD.
So on the first iteration, the map contains one element which is { 0xABCD, 1 }. On the second iteration it contains the same element with its value incremented, {0xABCD, 2}. On the third iteration it contains {0xABCD, 3}. Then when you go to print the map, it finds only one element in the map, and prints that memory address. This memory address happens to contain the word "cat", so it prints cat.
But this behavior is not reliable. The array char str[20] doesn't exist outside of the for loop, so sticking it into map <char *, int> cnt and even worse printing the array outside the loop are both undefined behavior.
If you want your code to work, I suppose you could do this....
for ( int i = 1; i <= n; i++){
char * str = new char[20];
gets(str);
cnt[str]++;
}
for ( auto i = cnt.begin(); i != cnt.end(); i++ )
puts(i->first);
for ( auto i = cnt.begin(); i != cnt.end(); i++ )
delete[](i->first);
But really, the correct strategy here is to either....
1) Use std::string
or
2) Don't use std::map
If you want to use C strings beyond converting them to std::string, then program without the use of the C++ std library. Stick to the C standard library.
Seems like cnt is std::map<char*, ...>. When you do cnt[str] you use pointer to local variable str as key, but str is only valid during single iteration. After that str is freed (semantically, optimizer may reuse it, but it is irrelevant here) and pointer to it is no longer valid.
It's very simple: when you allocate a C-style array as a local variable (char str[20];), it is allocated on the stack. It behaves just like any other object that you allocate as a local variable. And when it falls out of scope, it will be destroyed.
When you try to pass the array to the map in cnt[str], the array name decays to a pointer to the first element (it implicitely converts an expression of type char[20] into an expression of type char*). This is something radically different than an array. The map only ever sees this single pointer and stores it as the key. The map does not dereference the pointer to find out what's behind it, it just uses the memory location.
To fix your code, you need to do two things:
You need to allocate memory for your strings on the heap, so that the char* remains valid after the end of the scope. The easiest way to do this is to use the getline() or getdelim() functions available in the POSIX-2008 standard: These beautiful two functions will actually do the malloc() call for you. However, you still need to remember to free the string afterwards.
Making the map aware that you are talking about strings and not about memory addresses is much harder to achieve. If you must use a map, you likely need to define your own std::string-like wrapper class. But I guess, since you are playing around with the char* to learn their use, it would be more prudent to use some other kind of list and program the logic to check whether the given string is already in the list. Could be an array of char*, probably sorted to save lookup time, or a linked list, or whatever you like. For ease, you can just use an std::vector<char*>, but don't forget to free your strings before letting the vector fall out of scope.

C++ Assignment, strcpy and strlen with character arrays n pointers

I am working on this assignment and have encountered a problem. At one point, I have to ask the user for two input commands to be used later and I want them put in a char array. I then want to put the input they have into char* but I end up with a Segmentation fault
Here is a small part of my code that shows where I'm having problems:
#include <iostream>
#include <cstring>
using namespace std;
int main(){
char firstAns[80];
char * command1[5];
int ansLen;
//Ask for command
cout << "Please enter your first command(incl. args) or quit: ";
cin >> firstAns;
ansLen = strlen(firstAns);
for(int i=0; i < ansLen; i++){
strcpy(command1[i], firstAns);
}
The program that I ran this from compiles just fine but I have narrowed the segmentation fault to this part of the program and could use some help as a novice programmer :)
You have an array of char* called command. But you haven't allocated any memory for the pointers in the array, or even set them to null. SO they're random values, pointing to random memory locations. Strcpy is then overwriting those random locations, causing a seg fault. You need to allocate memory for those pointers by command[i]=new char[80] on all 5 rows first.
char * command1[5];
This is an array of char*s. However, it is uninitialized - the values can be any value, and as such they point to random, meaningless places in memory.
You then later use the uninitialized command1[i] in strcpy(command1[i], firstAns);. Essentially, what you have done is taken a random place in memory and tried to copy firstAns to it. No wonder your program crashes!
Before using a pointer, you have to initialize it to some value. If you need storage in memory, use malloc() to return storage of the correct size (sizeof(datatype)*length +1 if it is a string) and remember to free() the pointer returned from it when you're done with it.
Read more: http://www.cplusplus.com/reference/cstdlib/malloc/
(Gabe Sechan's solution is also valid. new and malloc are the C++ and C ways of allocating memory)
Additional Problem is here:
ansLen = strlen(firstAns);
for(int i=0; i < ansLen; i++){
strcpy(command1[i], firstAns);
}
ansLen is the length of firstAns, it may be possible that it is longer than 5. In this case,
if you try to access command1[i], you are going to access memory that out of bounds, results in segfault.
Meanwhile, you are using unitialized command1 as pointed out by Patashu and Gabe.

C++ Seg Fault at end of function. Reference line = closing brace

In conclusion: Thanks so much everyone! All the responses posted below were correct. The initial error was me forgetting to leave room for the NULL terminator. Strcpy() is a dangerous function because when I used it, it didn't know when the end of the 'string' was. Therefore, strcpy() grabbed to much data and overwrote the return address.
EDIT: added more code from the program
SOLVED: Honestly, my initial implementation was crap. I don't even know why I wrote swap that way if I wanted to swap out elements of the array. (At the time, each element only had the a char array in it. So I was able to get away with the old implementation). I have re-written it to:
void swap(ArrayElement list[], int index1, int index2) {
ArrayElement temp;
temp = list[index1];
list[index1] = list[index2];
list[index2] = temp;
}
I'm having problems with a segmentation fault at the end of the following function.
struct ArrayElement {
char data[SIZE_OF_ELEMENT];
// Implemented this way so that I can expand to multiple values later on
}
//In main:
ArrayElement* list = new ArrayElement[NUM_OF_ELEMENTS];
void swap(ArrayElement list[], int index1, int index2) {
char temp[SIZE_OF_ELEMENT];
strcpy(temp, list[index2].data);
strcpy(list[index2].data, list[index1].data);
strcpy(list[index1].data, temp);
}
The error is a segmentation fault at line 45, which is the ending curly brace of the function. This was compiled using g++. I used gbd to try and debug it and everything works correctly until it hits the curly brace.
I can give more code from the program if it is needed. I don't want to post the entire thing because this is for a class.
My best guess is, the string at list[index2].data is larger than temp[] and by copying, you overwrote the stack and the return address.
Try inserting a test for the length:
#include <iostream>
...
int n = strlen(list[index2].data);
std::cerr << "len=" << n << ", SIZE_OF_ELEMENT=" << SIZE_OF_ELEMENT << std::endl;
and see, if n (list[index2].data) is larger than SIZE_OF_ELEMENT
strcpy is a hazardous function. If the length of the input string is SIZE_OF_ELEMENT or more, you will write past the end of your temp array. If you must use a fixed size array as the output array in strcpy, you should test that the strcpy will work before using the function.
Even better is to switch from using char arrays to std::string.
Is data defined like this char data[SOME_CONSTANT]? If so then are you sure that SIZE_OF_ELEMENT is large enough? You are remembering the NULL terminator too, right?
If in ArrayElement data is defined like this char *data; and is allocated with malloc at a later time then are you sure that index1 has a buffer large enough for the data in index2 and vice versa? Again, you are remembering the NULL terminator too, right?