How can I understand this code (string as a function parameter in c) - string

I have written this code but its not working but when I replace *targ and *sour by targ[] and sour[] then its working. Also it shows many error when I call the function converge like this converge(*targ, *sour). Please someone help me to understand this.
#include<stdio.h>
#include<string.h>
void converge(char *target, char *src);
int main()
{
char *targ = "xxxxxxxxxxxxxxxxxxx";
char *sour = "yyyyyyyyyyyyyyyyyyy";
converge(targ, sour);
//printf("%s", targ);
}
void converge(char *target, char *src)
{
int i, j;
for(i=0,j=strlen(src); i<=j; i++, j--)
{
target[i]= src[i];
target[j]= src[j];
printf("%s\n",target);
}
}

If you define a string like this:
char *targ = "abcd";
it is treated as read-only value, since the string "abcd" is stored in read-only memory, while the pointer targ is stored on your stack. Depending on your compiler you might get some warning unless you make this more explicit with const char *targ = "abcd";. An assignment like targ[i] = src[i]; is not allowed in this case.
If you define a string like this:
char targ[] = "abcd";
a char-array will be created on your data stack, this string can be changed, since data on your stack is readable and writable. Additionally you can access the first element of your array as pointer.

Related

Error: this declaration has no storage class or type specifier ( Me making a simple struct. )

I was trying to make a simple struct to hold character stats.
This is what I came up with:
struct cStats
{
int nStrength;
int nIntelligence;
int nMedical;
int nSpeech;
int nAim;
};
cStats mainchar;
mainchar.nStrength = 10;
mainchar.nIntelligence = 10;
mainchar.nMedical = 10;
mainchar.nSpeech = 10;
mainchar.nAim = 10;
The mainchar. part is underlined red in visual studio, and when I mouse over it it shows this:
Error: this declaration has no storage class or type specifier
Any explanation of why it's doing this, and what I should be doing to fix it would be appreciated.
If this is C you should tag your question as such. cStats is a structure tag, not a type specifier. You need to declare mainchar as:
struct cStats mainchar;
If you wanted to use cStats as a type specifier you would define it as:
typedef struct
{
int nStrength;
int nIntelligence;
int nMedical;
int nSpeech;
int nAim;
} cStats;
If you did that your cStats mainchar would work.
Note that in C, char and character mean “ASCII alphanumeric character”, not “character in a play or game”. I suggest coming up with a different term for your program.
Another bit of advice; do not prefix your names with their data type; like nStrength for integer Strength. The compiler will tell you if you get your data types wrong, and if you ever need to change a type, for example to float nStrength to handle fractional Strengths, changing the name will be a big problem.
main(){
mainchar.nStrength = 10;
mainchar.nIntelligence = 10;
mainchar.nMedical = 10;
mainchar.nSpeech = 10;
mainchar.nAim = 10;}
These initialization should be written within the main() function.
Or else, write a init function and call it from main function.

C++/CX: Why doesn't returning a StringReference work like passing one as an argument?

Platform::StringReference exists so that you can pass a const wchar_t* across the ABI boundary to a function accepting a String^ without making a copy. The StringReference implicitly converts to a String^ whose internal pointer matches the original const wchar_t*. This is verified by the following code; if you step through it you find that pz == z:
void param(String^ s)
{
const wchar_t* z = s->Data();
}
App::App()
{
std::wstring p = L"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
const wchar_t* pz = p.c_str();
param(StringReference(pz));
}
However, trying to return a StringReference doesn't seem to work the same way and I'm curious why. If I have a function that returns String^ and I return a StringReference from it then the same implicit conversion operator is called, but when the caller gets their String^ it has a different internal data pointer that contains a copy. Here's some code that tries it:
String^ ret()
{
std::wstring s = L"12345678901234567890123456789012345678901234567890";
const wchar_t* z = s.c_str();
return StringReference(z);
}
App::App()
{
String^ r = ret();
const wchar_t* rz = r->Data();
}
That code verifies in two ways: first, if you step through you'll find that z != rz and second, r ends up pointing to a valid string rather than garbage, so a copy must have been made because the original string is freed at the end of ret.
I also tried returning via out parameter, but I get the same results as a straight return (z != oz and o ends up with a valid string):
void out(String^* r)
{
std::wstring s = L"12345678901234567890123456789012345678901234567890";
const wchar_t* z = s.c_str();
*r = StringReference(z);
}
App::App()
{
String^ o;
out(&o);
const wchar_t* oz = o->Data();
}
Is there a way to return a StringReference across the ABI boundary in the same way that you can pass one? I imagine the behavior would depend on the language of the caller and how that language marshals strings from WinRT, but it seems like at least a C++/CX caller ought to be able to do it.
No you can't return a StringReference across the ABI boundary. Returning a StringReference across the ABI boundary is similar (but not identical) to returning the address of a local variable. That's because the whole point of a StringReference is that the StringReference doesn't allocate any new memory.
Consider what would happen if you could return a StringReference across the ABI boundary. What would happen if you had:
String^ ReturnAString()
{
const wchar_t buffer[500] = "MyString";
return StringReference(buffer);
}
The StringReference is just a wrapper around the stack allocated buffer. And clearly you can't return that across the ABI boundary (the stack storage is reclaimed as soon as the routine exits).
Instead you need to return a real Platform::String - a Platform::String contains a copy of the string data and thus it can safely be returned to the caller.

C++/CLI from tracking reference to (native) reference - wrapping

I need a C# interface to call some native C++ code via the CLI dialect. The C# interface uses the out attribute specifier in front of the required parameters. That translates to a % tracking reference in C++/CLI.
The method I has the following signature and body (it is calling another native method to do the job):
virtual void __clrcall GetMetrics(unsigned int %width, unsigned int %height, unsigned int %colourDepth, int %left, int %top) sealed
{
mRenderWindow->getMetrics(width, height, colourDepth, left, top);
}
Now the code won't compile because of a few compile time errors (all being related to not being able to convert parameter 1 from 'unsigned int' to 'unsigned int &').
As a modest C++ programmer, to me CLI is looking like Dutch to a German speaker. What can be done to make this wrapper work properly in CLI?
Like it was also suggested in a deleted answer, I did the obvious and used local variables to pass the relevant values around:
virtual void __clrcall GetMetrics(unsigned int %width, unsigned int %height, unsigned int %colourDepth, int %left, int %top) sealed
{
unsigned int w = width, h = height, c = colourDepth;
int l = left, t = top;
mRenderWindow->getMetrics(w, h, c, l, t);
width = w; height = h; colourDepth = c; left = l; top = t;
}
It was a bit obvious since the rather intuitive mechanism of tracked references: they're affected by the garbage collector's work and are not really that static/constant as normal &references when they're prone to be put somewhere else in memory. Thus this is the only way reliable enough to overcome the issue. Thanks to the initial answer.
If your parameters use 'out' on the C# side, you need to define your C++/CLI parameters like this: [Out] unsigned int ^%width
Here's an example:
virtual void __clrcall GetMetrics([Out] unsigned int ^%width)
{
width = gcnew UInt32(42);
}
Then on your C# side, you'll get back 42:
ValueType vt;
var res = cppClass.GetMetrics(out vt);
//vt == 42
In order to use the [Out] parameter on the C++/CLI side you'll need to include:
using namespace System::Runtime::InteropServices;
Hope this helps!
You can use pin_ptr so that 'width' doesn't move when native code changes it. The managed side suffers from pin_ptr, but I don't think you can get around that if you want native code directly access it without 'w'.
virtual void __clrcall GetMetrics(unsigned int %width, unsigned int %height, unsigned int %colourDepth, int %left, int %top) sealed
{
pin_ptr<unsigned int> pw = &width; //do the same for height
mRenderWindow->getMetrics(*pw, h, c, l, t);
}

How to get a String^ into a 2d char array?

I'm trying to copy characters from a System::String ^ to a rectangular char array.
First I tried: (along with some other code. not relevant to the question)
char name[25][21];
...
void savedata(int x, System::String ^ a){ //x is the student #, a is the name
int b;
using namespace System::Runtime::InteropServices; // for class Marshal
char* buffer((char*)(void*)Marshal::StringToHGlobalAnsi(a));
x--; //So we write buffer[b] at data[0][b] when int x is 1
for(b = 0; b < 21; b++){
data[x][b] = buffer[b];
};
}
and when I tried to run and debug it, "An unhandled exception of type 'System.AccessViolationException'" occurred
Is there some easier/better way to put a String^ into a (2 dimensional) char array, and if not, what am I doing wrong here?
You should be calling .ToPointer() to convert the result of StringToHGlobalAnsi to something that you can then cast to char*.
You should also call FreeHGlobal on the result of StringToHGlobalAnsi (or you can recreate an IntPtr from your char*).

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