VC++ read variable length char* - visual-c++

I'm trying to read a variable length char* from the user input. I want to be able to specify the length of the string to read when the function is called;
char *get_char(char *message, unsigned int size) {
bool correct = false;
char *value = (char*)calloc(size+1, sizeof(char));
cout << message;
while(!correct) {
int control = scanf_s("%s", value);
if (control == 1)
correct = true;
else
cout << "Enter a correct value!" <<endl
<< message;
while(cin.get() != '\n');
}
return value;
}
So, upon running the program and trying to enter a string, I get a memory access violation, so I figured something has gone wrong when accessing the allocated space. My first idea was it went wrong because the size of the scanned char * is not specified within scanf(), but it doesn't work with correct length strings either. Even if I give the calloc a size of 1000 and try to enter one character, the program crashes.
What did I do wrong?

You have to specify the size of value to scanf_s:
int control = scanf_s("%s", value, size);
does the trick.
See the documentation of scanf_s for an example of how to use the function:
Unlike scanf and wscanf, scanf_s and wscanf_s require the buffer size to be specified for all input parameters of type c, C, s, S, or [. The buffer size is passed as an additional parameter immediately following the pointer to the buffer or variable.
I omit the rest of the MSDN description here because in the example they're providing, they use scanf instead of scanf_s what is quite irritating...

Related

How to make an array of pointers and make the user enter the size of it?

I want to make an array, and inside this array there are pointers, like this:
int *arrp[size]; and I want the user to enter the size of it.
I tried to do this:
#include <iostream>
using namespace std;
int main ()
{
int size;
cout << "Enter the size of the array of pointers" << endl;
cin >> size;
int *arrp[size];
return 0;
}
but this doesn't work.
I also tried to do this:
#include <iostream>
using namespace std;
int main ()
{
int size;
cout << "Enter the size of the array of pointers" << endl;
cin >> size;
int* arrp[] = new int[size];
return 0;
}
also doesn't work, can someone help?
The error of the first code is that the size must be constant, I tried to fix that by writing the 2nd code but it gives an error for the word "new" in line 9:
E0520 initialization with '{...}' expected for aggregate object
and another error for the size in the same line:
C2440 'initializing': cannot convert from 'int *' to 'int *[]'
To make an array of pointers you should type: int** arr = new int*[size]
we type 2 stars '*', the first mean a pointer to an integer, the second means a pointer to the pointer to the integer, and then we make a place in the memory for those pointers by typing = new int*[size], you can use this as a 2D array that stored in the heap (not the stack) go to this website to know the difference: https://www.geeksforgeeks.org/stack-vs-heap-memory-allocation/.
to know more about how to use an array of pointers to a pointer to an integers you can see this video: https://www.youtube.com/watch?v=gNgUMA_Ur0U&ab_channel=TheCherno.

"Stack around the variable was corrupted" error

I'm trying to read a char value using fgets as follows:
int main() {
char m_cityCharCount;
// Input the number of cities
fgets(&m_cityCharCount, 4, stdin);
return 0;
}
Visual Studio returns this error after the code is executed - Stack around the variable m_cityCharCount was corrupted
Is there something I can do about it?
m_cityCharCount is a char, it can hold one char at the most, but you are telling fgets it is 4 bytes buffer. Even if you input nothing but hit the enter key, fgets will store the new line AND the null terminator to the buffer, which of cause is a serious problem. You need a bigger buffer to do fgets:
char str[4096];
fgets(str, sizeof str, stdin);
First parameter of fgets() is pointer on buffer (size of it should be great or equals than second parameter. But sizeof(char) == 1)
int main() {
char m_cityCharCount[4];
// Input the number of cities
fgets(m_cityCharCount, 4, stdin);
return 0;
}

How can I get the value of a registry key in c++ without an access violation?

Hey I'm new to C++ and I am trying to find out if a specified registry index exists. I have to check multiple locations due to the possibility of the software being run on a 64bit machine and being under the WOW6432Node key instead of the usual position. When RegQueryValueExA (using visual c++ 6.0 on xp so I can't use a newer function) is run it should return a Boolean of true if the key exists, (I'll deal with getting the value of the key later). However on run it generates access violation 0xc00005. Any ideas whats gone wrong?
bool FindAndRemoveUninstall(string path){
bool result;
result = RegQueryValueExA(HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ABC"), NULL, NULL, NULL, (unsigned long *)MAX_PATH);
if (result= ERROR_SUCCESS){
cout <<" is a 32 bit program\n";
//path= Value in key
}
result = RegQueryValueEx(HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ABC"), NULL, NULL, NULL, (unsigned long *)MAX_PATH);
if (result= ERROR_SUCCESS){
cout << " is 64 bit program\n";
//path= Value in key
}
return true;
}
You have multiple problems.
The last parameter to RegQueryValueExA is documented as
lpcbData [in, out, optional]
A pointer to a variable that specifies the size of the buffer pointed to by the lpData parameter,
But you are not passing a pointer to a variable. You are passing (unsigned long *)MAX_PATH, which is a garbage pointer. When the operating system tries to store the result into the pointer, it takes an access violation. You need to pass a pointer to a variable, like the documentation says.
The next problem is that you are calling the A function (explicit ANSI) but using the TEXT macro (adaptive character set). Make up your mind which model you are using (ANSI or adaptive) and choose one model or the other. Let's assume you explicit ANSI.
The next problem is that you didn't specify an output buffer, so you don't actually retrieve the path.
Another problem is that the RegQueryValueExA function does not return a bool; it returns an error code.
Yet another problem is that your if test contains an assignment, so it does not actually test anything.
Another problem is that you didn't specify a way for the function to return the path to the caller. Let's assume you want the result to be returned in the path parameter.
Yet another problem is that you have the 32-bit and 64-bit cases reversed.
Also, you are using '\n' instead of std::endl.
The eight problem is that your function returns true even if it didn't do anything.
And the ninth problem is that the function says FindAndRemove, and it finds, but doesn't remove.
bool FindUninstall(string& path){ // parameter passed by reference, fix function name
LONG result; // change variable type
char buffer[MAX_PATH]; // provide an output buffer
DWORD bufferSize = MAX_PATH; // and a variable to specify the buffer size / receive the data size
result = RegQueryValueExA(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ABC", NULL, NULL, (LPBYTE)buffer, &bufferSize); // remove TEXT macro, pass the buffer and buffer size
if (result== ERROR_SUCCESS){ // fix comparison
cout <<" is a 64 bit program" << std::endl; // fix message
path = buffer;
return true; // stop once we have an answer
}
buffersize = MAX_PATH; // reset for next query
result = RegQueryValueEx(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ABC", NULL, NULL, (LPBYTE)buffer, &bufferSize); // remove TEXT macro, pass the buffer and buffer size
if (result== ERROR_SUCCESS){ // fix comparison
cout << " is 32 bit program" << std::endl; // fix message
path = buffer;
return true; // stop once we have an answer
}
return false; // nothing found
}
Since you are new to C++, I would recommend that you get some experience with C++ doing simpler projects before diving into more complicated things like this.

Arena Allocator Allocation Method & Violation Writing Issue

Basically I'm trying to create an Arena Allocator without using structs, classes, or the new operator to manually manage memory. I have a defined size, a character pool, an allocation method and a freeMemory display method.
Note that pool[0] is my index which will keep track of where the memory has last been filled.
const int size = 50000;
char pool[size];
void start() {
pool[0] = 1;
}
int freeMemory(void) {
int freemem = 0;
for(int i = 0; i < size; i++) {
if(pool[i] == NULL) {
freemem++;
}
}
return freemem;
}
void* allocate(int aSize)
{
if(freeMemory() == 0)
{
out();
}
else
{
char* p = NULL;
int pos = pool[0];
pool[pos] = (char) a;
p = &pool[pos];
pool[0] += a;
return((void*) &pool[pos]);
}
}
In the main.cpp:
start();
long* test1 = (long *) allocate(sizeof(long));
cout << freeMemory() << endl; //Returns 49999
*test1 = 0x8BADF00D; //Breaks here
cout << freeMemory() << endl;
It breaks when I try to use 0x8BADF00D and I believe I'm having issues initializing some of these variables too.
Unhandled exception at 0x000515f7 in MemoryManagerC.exe: 0xC0000005: Access violation writing location 0x00000004 on 0x8BADF00D
The code below has numerous bugs.
char* pointer;
for(int i = 0; i < size; i++)
{
*pointer = pool[i];
if(pointer != NULL)
{
pointer = (char*) a;
return((void*) i); //return the pointer
}
}
This line copies a character to an unknown memory location. Since pointer has never been initialized, we can only guess where it's pointing
*pointer = pool[i];
You probably meant to copy a pointer.
pointer = &pool[i];
Although if you did mean to copy a pointer from the pool array, this will always be true. None of the elements in that array reside at address NULL.
if(pointer != NULL)
Now this code changes pointer to point to...more invalid addresses. When a is sizeof(long), that size is reinterpreted to be a memory address. Memory address 0x00000004 most likely.
pointer = (char*) a;
And then this will return the address 0x00000000, in your case. Because i is 0.
return((void*) i); //return the pointer
There are some problems with allocate:
char* pointer = NULL;
int pos = pool[0];
pool[0] is a char. It's not big enough to store indexes to all members of the array.
pool[pos] = (char) a;
I'm not sure what you're storing here, or why. You seem to be storing the size of the allocation in the space that you're allocating.
pointer = &pool[pos + a];
I think you're constructing a pointer to the memory after the allocated portion. Is that right?
pool[0] += a;
And here you're incrementing the offset that shows how much of the pool is allocated, except that a single char isn't going to be big enough for more than a tiny quantity of allocations.
return((void*) &pointer);
And now you're returning the address of the pointer variable. That's going to be an address on the stack, and unsafe to use. Even if you just the contents of pointer instead of its address, I think it would point after the region you just allocated in your pool.
There are also problems with freeMemory. It compares the contents of the pool (char elements) with NULL. This suggests you think it contains pointers, but they are just chars. It's not clear why unallocated parts of the pool would be 0. Do you even allow deallocation within the pool?
Perhaps you could explain how you intend the allocator to work? There's obviously a gap between what you think it should do and what it actually does, but it's not clear what you think it should do, so it's hard to give advice. How do you apportion space in the array? Do you allow deallocation? What information is supposed to be encoded where?
I just realised that allocate uses the undefined variable a. Is that supposed to be the same thing as the parameter aSize? That's what I assume here.
a possible problem with your code might be here.
char* pointer;
for(int i = 0; i < size; i++)
{
*pointer = pool[i];
The thing here is this might work on some compilers (it shouldn't in my opinion).
pointer here is not pointing to anything allocated. So when you do
*pointer = pool[i];
Where should pool[i] be copied to?
For example let's say we delclared pointer like this.
char* pointer = NULL;
now it is clear that
*pointer = pool[i];
is wrong.
g++ (I have noticed) initializes pointers to NULL. So your code will segfault. VC++ might work because it didn't NULL initialize pointer. But you are writing to a memory location that's not yours.

Having trouble passing array to function

I am getting all kinds of errors when passing my array to this function. The function is suppose to have the user enter a name and a score and store them in 2 seperate arrays, one for the names, one for the scores. I believe I have to use pointers but have no idea on how to use them. I don't want the answer, just a push in the right direction. Here is the code:
#include <iostream>
int InputData(int &, char, int);
using namespace std;
int main()
{
char playerName[100][20];
int score[100];
int numPlayers = 0;
InputData(numPlayers, playerName, score);
return 0;
}
int InputData(int &numPlayers, char playerName[][20], int score[])
{
while (numPlayers <= 100)
{
cout << "Enter Player Name (Q to quit): ";
cin.getline(playerName, 100, ā€˜\nā€™);
if ((playerName[numPlayers] = 'Q') || (playerName[numPlayers] = 'q'))
return 0;
cout << "Enter score for " << playerName[numPlayers] <<": ";
cin >> score[numPlayers];
numPlayers++;
}
}
Ok, I made some more changes and the errors are less, must be getting close, Lol!
This looks like a school assignment and I applaud you for not asking for the answer. There are several ways to do it, but you are already fairly close in the approach that you are using. When you pass an array reference, you do not want to include the length of the array. For example, the parameter int score[100] should be int score[]. The exception, especially in your scenario, is with multidimensional arrays. In this case, you want to use char playerName[][20]. Your function declaration also needs to change to match. Don't forget InputData returns an int. Your declarations and function call are correct; you just need to adjust your function signature.
Keeping the errors aside -
InputData(numPlayers, playerName, score, size);
// ^^^^ size is no where declared
// resulting Undeclared indentifier error
Prototype mentions of taking 3 arguments but calling the function passing 4 parameters.
Hint regarding errors:
An 1D array decays to a pointer pointing to first element in the array while passing to a function.
A 2D array decays to a pointer pointing to the 1D array ( i.e., T[][size] ) while passing to a function.
Return type of main() should be int.
It seems with the given hints you corrected most of the errors. But you forgot to change the prototype. So, change -
int InputData(int &, char, int);
to
int InputData(int &, char[][20], int[]);
Why aren't you using std::string array for player names ? Use it and remove rest of the errors. Good luck.

Resources