In C#, if I were to create an array of string arrays it is easy as doing:
string[,] array = new string[50,7];
How would I go about doing that in C? I do understand that I should make use of pointers but what I have come up with doesn't seem to work properly.
char *array[50][7];
Please note that I'm not looking to set the elements to constant values, I need to be able to access them/set them in the program again either by means of using the scanf() function or simply with = if possible. What is the simplest way of achieving this?
EDIT: Am I doing something wrong here? The following very simple example crashes the program:
char *username;
printf("Username: ");
scanf("%s", &username);
array[0][0] = malloc(strlen(username) + 1);
strcpy(array[0][0], username);
I have, in fact, added a reference to stdlib.h
There is no easy way :) Since C has no high level string class, at least not without invoking some non-standard library.
To be flexible you would indeed need a 2D array of pointers char *array[50][7];, where every pointer is set to point at the actual string. Upon creating a string, you will have to allocate enough memory to hold it, plus the null terminator, by using malloc(). For example:
array[x][y] = malloc(strlen(the_string) + 1);
assert(array[x][y] != NULL);
It is not possible to copy strings in C with the = assignment operator, so after allocating the memory, you have to copy the string into the allocated memory area by using strcpy.
strcpy(array[x][y], the_string);
The following code crashes as code is attempting to save scanf() input to the place pointed to by username, yet username is not initialized.
char *username;
scanf("%s", &username); // bad
Instead, could use
char username[100];
scanf("%99s", username);
Or better
char username[100];
fgets(username, sizeof username, stdin);
username[strcspn(username, "\n")] = '\0'; // lop off potential \n
It appear OP wants a 50 x 7 array of pointers to C strings allocated like in string[,] array = new string[50,7];
Recall, in C, a string is itself a character array ending with a null character
#include <stdlib.h>
typedef char *a50_7_T[50][7];
a50_7_T *a50_7_alloc(void) {
a50_7_T *a = malloc(sizeof *a);
for (int i=0; i<50; i++) {
for (int j=0; j<7; j++) {
(*a)[i][j] = NULL; // or whatever OP wants as initial state
}
}
return a;
}
void a50_7_free(a50_7_T *a) {
for (int i=0; i<50; i++) {
for (int j=0; j<7; j++) {
free((*a)[i][j]);
}
}
free(a);
}
// Sample usage code
#include <string.h>
void foo(void) {
a50_7_T *a = a50_7_alloc();
printf("Size %zu\n", sizeof *a); // e.g. "Size 1400"
(*a)[0][0] = strcpy(malloc(6), "Hello");
a50_7_free(a);
}
OTOH if OP want to create the array as part of the declaration, what OP did was on the right track.
// Initialize all to zeros, (NULL)
char *array[50][7] = { 0 };
...
array[0][0] = strcpy(malloc(6), "Hello");
...
free(array[0][0]);
The array is ok as that. The problem may come from strings. C 'strings' are very low level, and can't really be compared to C# strings. You will have to manually allocate and deallocate space for them. If you plan on using scanf on them, you can allocate a buffer for each one, but you will have problems if you find a string longer than the buffer. You can assign them with '=', but only if you handle deallocation of the old value. Maybe you can check a library such as 'glib' to do some of the work for you.
Well, you have to decide two things where C# simply doesn't give you a choice (or at least, the standard one is very strongly recommended):
How do you want to represent your 2-dimensional array?
You have the choice between, among others,
a single-dimensional array and explicit pointer-arithmetic,
a pointer to a 2-dimensional array with one fixed dimension,
a pointer to a 1-dimensional array of pointers to 1-dimensional arrays.
How do you want to represent your string?
Decide on the code-unit: char (hopefully 8-bit), wchar16_t, wchar32_t, wchar_t?
Counted strings or 0-terminated?
In a fixed-size-buffer or dynamically allocated?
Related
I need to count the size, in bytes, that a substring will be once converted into a UTF8 byte array. This needs to happen without actually doing the conversion of that substring. The string I'm working with is very large, unfortunately, and I've got to be careful not to create another large string (or byte array) in memory.
There's a method on the Encoding.UTF8 object called GetByteCount, but I'm not seeing an overload that does it where I don't have to copy the string into a byte array. This doesn't work for me:
Encoding.UTF8.GetByteCount(stringToCount.ToCharArray(), startIndex, count);
because stringToCount.ToCharArray() will create a copy of my string.
Here's what I have right now:
public static int CalculateTotalBytesForUTF8Conversion(string stringToCount, int startIndex, int endIndex)
{
var totalBytes = 0;
for (int i = startIndex ; i < endIndex; i++)
totalBytes += Encoding.UTF8.GetByteCount(new char[] { stringToCount[i] });
return totalBytes;
}
The GetByteCount method doesn't appear to have the ability to take in just a char, so this was the compromise I'm at.
Is this the right way to determine the byte count of a substring, after conversion to UTF8, without actually doing that conversion? Or is there a better method to do this?
There doesn't appear to be a built-in method for doing this, so you could either analyze the characters yourself or do the sort of thing you're doing above. The only thing I would recommend -- reuse a char[1] array, rather than creating a new array with each iteration. Here's an extension method that jives well with the built-in methods.
public static class EncodingExtensions
{
public static int GetByteCount(this Encoding encoding, string s, int index, int count)
{
var output = 0;
var end = index + count;
var charArray = new char[1];
for (var i = index; i < end; i++)
{
charArray[0] = s[i];
output += Encoding.UTF8.GetByteCount(charArray);
}
return output;
}
}
So, there is an overload which doesn't require the caller create an array of characters first: Encoding.GetByteCount Method (Char*, Int32)
The issue is that this isn't a CLS-compliant method and will require you do some exotic coding:
public static unsafe int CalculateTotalBytesForUTF8Conversion(
string stringToCount,
int startIndex,
int endIndex)
{
// Fix the string in memory so we can grab a pointer to its location.
fixed (char* stringStart = stringToCount)
{
// Get a pointer to the start of the substring.
char* substring = stringStart + startIndex;
return Encoding.UTF8.GetByteCount(substring, endIndex - startIndex);
}
}
Key things to note here:
The method has to be marked unsafe, since we're working with pointers and direct memory manipulation.
The string is fixed for the duration of the call in order prevent the runtime moving it around - it gives us a constant location to point to, but it prevents the runtime doing memory optimization.
You should consider doing thorough performance profiling on this method to ensure it gives you a better performance profile than simply copying the string to an array.
A bit of basic profiling (a console application executing the algorithms in sequence on my desktop machine) shows that this approach executes ~35 times faster than looping over the string or converting it to a character-array.
Using pointer: ~86ms
Looping over string: ~2957ms
Converting to char array: ~3156ms
Take these figures with a pinch of salt, and also consider other factors besides just execution speed, such as long-term execution overheads (i.e. in a service process), or memory usage.
How do I access a managed 2D array on the C++ side?
I know we are supposed to use pin_ptr<T> in order to access the managed array from the C++ side. It's straightforward with a 1D array, but with a 2D array I don't know how to use pin_ptr<T> correctly.
My code looks like this, where foo() will be called from the C# side:
nativeFunc(double **ptr);
foo(array<double,2> ^A)
{
const int len = A->GetLength(0);
double **ptr = (double**) alloca(sizeof(double*) * len);
for(int i = 0; i < len; i++)
{
pin_ptr<double> pinned = &A[i,0]; //Will go out of scope!
ptr[i] = pinned;
}
nativeFunc(ptr);
}
The problem is that my pin_ptr<T> will go out of scope too early, as it's located inside the loop body, and thus I think above code is NOT safe. But how can I avoid this? Apparently, it's not allowed to make an array of pin_ptr<T>, neither managed nor unmanaged. It also cannot be added to a std::vector and it cannot be made a class member either. So I'm kind of stuck here...
Thanks for any suggestions...
Okay, after some more digging, I found out that GCHandle::Alloc(x, GCHandleType::Pinned) may work as a more flexible replacement for pin_ptr<T> here. However, it seems we can only pin down the managed array as a whole. It does not seem to be possible to pin down a single sub-array (inner array) this way, like the pin_ptr<T> would do. Furthermore, by "try and error" method I have figured out that from the GCHandle handle I can get an unmanaged pointer via hdl.AddrOfPinnedObject().ToPointer() and that this one points to a continuous block of memory which contains the whole 2D array in a "flattened" (serialized) form. From here I can reconstruct the unmanaged 2D array, by using the proper base-pointer and stride. But is this considered a "safe" method and does it always work or is it even implementation specific ???
So I have hacked together a solution like this:
class ArrayPinHandlerRAII
{
public:
ArrayPinHandlerRAII(array<double,2> ^managedArray)
{
m_dimOuter = managedArray->GetLength(0);
m_dimInner = managedArray->GetLength(1);
m_handle = GCHandle::Alloc(managedArray, GCHandleType::Pinned);
m_ptr = new double*[m_dimOuter];
double *basePointer = reinterpret_cast<double*>
(m_handle.AddrOfPinnedObject().ToPointer());
for(size_t d = 0; d < m_dimOuter; d++)
{
m_ptr[d] = basePointer;
basePointer += m_dimInner;
}
}
~ArrayPinHandlerRAII(void)
{
delete [] m_ptr;
m_handle.Free();
}
inline double **data(void)
{
return m_ptr;
}
inline const size_t &dimOuter(void) const
{
return m_dimOuter;
}
inline const size_t &dimInner(void) const
{
return m_dimInner;
}
private:
GCHandle m_handle;
double **m_ptr;
size_t m_dimOuter;
size_t m_dimInner;
};
Any opinions? ;-)
Okay, one of the examples in MSDN has the following important info:
Pinning a sub-object defined in a managed object has the effect of pinning the entire object. For example, if any element of an array is pinned, then the whole array is also pinned. There are no extensions to the language for declaring a pinned array. To pin an array, declare a pinning pointer to its element type, and pin one of its elements.
So the code can actually be simplified to:
void nativeFunc(double **ptr);
void foo(array<double,2> ^A)
{
int dimOuter = managedArray->GetLength(0);
int dimInner = managedArray->GetLength(1);
pin_ptr<double> pinned = &A[i,0]; //This pins the *entire* array!
double **ptr = (double**) alloca(sizeof(double*) * dimOuter);
double *basePtr = pinned;
for(int i = 0; i < dimOuter; i++)
{
ptr[i] = basePtr;
basePtr += dimInner;
}
nativeFunc(ptr);
}
I am new at C#, so sorry for the basic question :)
I have a text box, in this text box i write an input.
And then I want an output with only the uneven number position of the string.
So I wrote a for loop...
string strVariable = txt.Text;
for (int c = 0; c > strVariable.Length; c++)
{
string[] Array = new string[strVariable.Length];
Array [c] = strVariable.Substring(c, 1);
}
But how can I now enter all the values of the Array in one string?
So for example I have the word "Test" in the strVariable string
Then in the Array string I have "Ts"
but how can I output "Ts"
There are undoubtedly many ways to collapse an array of strings into a single string. One such way would be to use string.Concat():
var result = string.Concat(myArray);
Note that I rename your variable to myArray here. For starters, you'll want to follow language conventions with variable names which in this case specify that the first letter should be lowercase. But more importantly, you definitely don't want to name a variable with the same name as a class in a namespace that you're using. That would cause untold confusion.
I think you should use a simple for loop without using an array like in the code below :
string result;
for (int c = 0; c < txt.text.Length; c++)
{
result += txt.text.Substring(c, 1);
}
Say I want to get the third letter in a string.
string s = "cats";
what is the difference between using s[2] to get the value,
as I see most examples online use:
char[] c = s.ToCharArray();
char x = c[2];
If you need a char at particular index, use "cats"[2]
If you need the whole string as char array, use "cats".ToCharArray()
The s[2] method simply looks up the character in that position and returns it.
The s.ToCharArray(); method allocates a new char[], then c[2] looks it up in the array.
If you need just a single character, use the s[2] method as the ToCharArray() method is wasteful. If you need all the characters in the string as a char[] then the ToCharArray() method is cleaner and probably faster (I haven't done any benchmarking, so don't hold me to that).
EDIT:
Both MS.NET and Mono's implementations of string.ToCharArray() use unsafe code that pins the internal char and a duplicate char[] and operates on the pointers. This is definitely faster than calling the indexer for every character and is probably faster than using an enumerator to iterate over all the characters. Plus I find it a lot cleaner, especially in the case where it's used as a parameter:
DoSomethingWithCharArray(s.ToCharArray());
vs
int i = 0;
char[] arr = new char[s.Length];
foreach (char c in s)
{
arr[i] = c;
i++;
}
DoSomethingWithCharArray(arr);
or
char[] arr = new char[s.Length];
for (int i = 0; i < s.Length; i++)
{
arr[i] = s[i];
}
DoSeomthingWithCharArray(arr);
The difference is exactly that you're creating a character array unnecessarily. Use s[2].
If you're just reading the character the difference is only a slightly larger memory footprint. However, if you also want to change some characters and retain the original string then utilizing ToCharArray is very usefull.
I am having a really hard time getting this marshalling down.
I have umanaged code that looks like this:
WORD HLP_GetDeviceNames (LPSTR *DevNames, WORD Max_Len, WORD Max_Num)
Just FYI I did not write this unmanaged code but must use it.
Returns: WORD indicating an error.
DevNames: Pointer to an array of char arrays. Basically an array of strings that will be modified and returned back to me!
Max_Len: Length of each string (I am told this must be 256)
Max_Num: Length of array. I am using another Invoke call that is working that tells me number of devices so i know exactly how many strings to send.
I have used P/Invoke interop signatureToolkit to figure alot of this out but also read a bunch to get even further. Where I am now is here:
[DllImport("UsbMeasLib.dll")]
public static extern ushort HLP_GetDeviceNames([MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr)] ref StringBuilder[] DevNames, ushort Max_Len, ushort Max_Num);
I call my code like this:
StringBuilder[] DevNames = new StringBuilder[deviceCount];
for(int i = 0; i< deviceCount; i++)
{
DevNames[i] = new StringBuilder().Append(' ', 256);
}
HachUsbMeasLib.HLP_GetDeviceNames(ref DevNames, 256, Convert.ToUInt16(DevNames.Count()));
I am using string builder array because I need the unmanaged code to modify the string builder so that it can return the new string since string is unmutable.
When I run the code, My array is unmodified!
I'm not really sure what is going on but I think it has something to do with CLR telling unmanaged code to not modify my array in place but instead creates a new reference(pointer). Even if this is the case, I dont know how to fix it.
Thanks for any insight anybody can offer!
Try to work on low level. Declare DevNames parameter as IntPtr[]. Prepare it by the following way:
IntPtr[] devNames = new IntPtr[deviceCount];
for(int i = 0; i < deviceCount; i++)
{
devNames[i] = Marshal.AllocHGlobal[256];
}
Pass this array to HLP_GetDeviceNames. To handle output data, apply Marshal.PtrToStringAnsi to every DevNames member. Don't forget to release DevNames[i] with Marshal.FreeHGlobal in the end.
I figured this one out. Thanks to anybody who replied.
I found out how it works. I simply supply the memory space but I have to let the marshaling know that I expect in and out with this object so it allows the unmanaged code to modify the allocated space.
I did it like this:
[DllImport("UsbMeasLib.dll")]
private static extern ushort HLP_GetDeviceNames([In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr)] string[] DevNames, ushort Max_Len, ushort Max_Num);
I use string instead of string builder because the unmanaged code will simply replace the string which is ok. I am getting the array pointer back, not modified strings. the managed code is just changing an array of pointers to point to new string objects (I think).
int numDev = HLP_GetNumDevices();
string[] names = new string[numDev];
for (int i = 0; i < names.Length; i++)
{
names[i] = new StringBuilder().Append(' ', 256).ToString();
}
ushort errorCode = HLP_GetDeviceNames(names, 256, Convert.ToUInt16(numDev));
I allocate memory for the unamanged code then let the unmanaged code chane the strings there.
This works but I dont know if I have any potential memory leaks or other potential problems.