Sign in to follow this  
Followers 0
FaridAgl

CSV variable to array - C++

33 posts in this topic

I'm trying to parse this:

char *szCSV = "1,qw.ryui-opas_fgh,6da1ef8d8fc0cafcwfcc9r34d8302cb3,asdfasda85ffcfes7f2v1sfdfsd1f4ss";

To something like this:

char *szArr[] = {"1", "qw.ryui-opas_fgh", "6da1ef8d8fc0cafcwfcc9r34d8302cb3", "asdfasda85ffcfes7f2v1sfdfsd1f4ss"};

Any help/tips would be great.

Share this post


Link to post
Share on other sites



Replace any commas with null characters, and store the pointers to the first character of each item.

Share this post


Link to post
Share on other sites

Thanks Mat, I can imagine how that should work, but I guess I don't have the enough skill for that.

Can I ask for a working code please? However I'm going to try it.

Share this post


Link to post
Share on other sites

Working example would really depend on your actual code. The way you've put things, Mat's idea wouldn't work because szCSV is read-only.


♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

Well, you are right.

LPSTR szCSV = "1,qw.ryui-opas_fgh,6da1ef8d8fc0cafcwfcc9r34d8302cb3,asdfasda85ffcfes7f2v1sfdfsd1f4ss";

DWORD i = 0;
while (szCSV[i] != NULL)
{
    if (szCSV[i] == ',')
    {
        szCSV[i] = NULL;
    }

    i++;
}

This code gives me "Access violation writing location" error.

I'm working on a socket server, a multithread one, here it is:

#define RECV_BUF_LEN 92

DWORD WINAPI ClientSocketThread(LPVOID lpParameter)
{
    SOCKET s = *(SOCKET *)lpParameter;

    char buf[RECV_BUF_LEN];

    if (recv(s, buf, RECV_BUF_LEN, 0) <= 0)
    {
        closesocket(s);

        printf_s("recv failed.\n");
        return 0;
    }

    char msg[] = "Thanks, I've read that.";
    send(s, msg, strlen(msg), 0);

    if (shutdown(s, SD_BOTH) == SOCKET_ERROR)
    {
        closesocket(s);

        printf_s("shutdown failed.\n");
        return 0;
    }

    closesocket(s);
    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
    WSADATA WSAData;
    if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)
    {
        printf_s("WSAStartup failed.\n");
        goto Finish;
    }
    else
    {
        if (LOBYTE(WSAData.wVersion) != 2 || HIBYTE(WSAData.wVersion) != 2)
        {
            WSACleanup();

            printf_s("Could not find a usable version of Winsock.dll.\n");
            goto Finish;
        }
    }

    addrinfo Hints;
    ZeroMemory(&Hints, sizeof(Hints));
    Hints.ai_family = AF_INET;
    Hints.ai_socktype = SOCK_STREAM;
    Hints.ai_protocol = IPPROTO_TCP;
    Hints.ai_flags = AI_PASSIVE;

    addrinfo *Result = NULL;

    if (getaddrinfo("127.0.0.1", "1234", &Hints, &Result) != 0)
    {
        WSACleanup();

        printf_s("getaddrinfo failed.\n");
        goto Finish;
    }

    SOCKET s = socket(Result->ai_family, Result->ai_socktype, Result->ai_protocol);
    if (s == INVALID_SOCKET)
    {
        freeaddrinfo(Result);
        WSACleanup();

        printf_s("socket failed.\n");
        goto Finish;
    }

    if (bind(s, Result->ai_addr, (int)Result->ai_addrlen) == SOCKET_ERROR)
    {
        closesocket(s);
        freeaddrinfo(Result);
        WSACleanup();

        printf_s("bind failed.\n");
        goto Finish;
    }

    freeaddrinfo(Result);

    if (listen(s, SOMAXCONN) == SOCKET_ERROR)
    {
        closesocket(s);
        WSACleanup();

        printf_s("listen failed.\n");
        goto Finish;
    }

    SOCKET socket = INVALID_SOCKET;
    while (true)
    {
        socket = accept(s, NULL, NULL);
        if (socket == INVALID_SOCKET)
        {
            printf_s("accept failed.\n");
            continue;
        }

        CreateThread(NULL,
            0,
            (PTHREAD_START_ROUTINE)ClientSocketThread,
            &socket,
            0,
            NULL);
    }

    closesocket(s);
    WSACleanup();

Finish:
    system("Pause");
    return 0;
} 

It receives the message sent by the client (which will be CSV formatted), and will send the proper data back.

Currently I'm on the "CSV Parser" step! And I have to parse buf variable in the ClientSocketThread to an array, like I had explained in the first post.

Share this post


Link to post
Share on other sites

It's ok then because your buf is allocated on the stack, you can do whatever you want with it, meaning your OP's szCSV is more like this:

char szCSV[] = "1, qw.ryui - opas_fgh, 6da1ef8d8fc0cafcwfcc9r34d8302cb3, asdfasda85ffcfes7f2v1sfdfsd1f4ss";

♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

Yes, my miss, thanks.

Any change of seeing any example? I can replace commas with null but I'm not able to create a new variable for each of them (Something like what Mat said).
I guess I don't have the skill.

Thanks in advance.

Share this post


Link to post
Share on other sites

This could be one way to do what you want:

char buf[RECV_BUF_LEN] = {}; // zero-ed out

//...the rest of your code that fills the buf...

// Calculate how many chunks of strings are in your buf
int ibound = 0;
for (int i = 0; i < RECV_BUF_LEN; ++i)
{
    if (buf[i] == ',')
    {
        buf[i] = '\0';
        ++ibound;
    }
}

// Now you allocate space for calculated number of (string) pointers
char** szArr = new char*[ibound + 1];

for (int j = 0, i = 0; j <= ibound; ++j)
{
    szArr[j] = &buf[i]; // set this pointer to your array
    for (; i < RECV_BUF_LEN; ++i)
    {
        if (buf[i] == '\0')
        {
            ++i; // skip this one
            if (buf[i] == ' ') ++i; // skip "space" too
            break;
        }
    }
}

// Print elements of your array just because
for (int i = 0; i <= ibound; ++i)
printf("%i. %s\n", i, szArr[i]);

// Free dynamically allocated array (don't forget this)
delete[] szArr;

fflush(stdout); // flush to see what's printed

♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

#define LPSTR char*
#define TCHAR char
#define DWORD unsigned long


#include <string.h>
#include <stdio.h>


#define RECV_BUF_LEN 92

LPSTR szCSV = "1,qw.ryui-opas_fgh,6da1ef8d8fc0cafcwfcc9r34d8302cb3,asdfasda85ffcfes7f2v1sfdfsd1f4ss";


int main() {
    TCHAR buff[92];
    LPSTR parts[4] = {buff, 0}; // Assuming there is always 4 elements?

    // Mimics the recieving from the socket
    strncpy(buff, szCSV, RECV_BUF_LEN);

    TCHAR* ch = &buff[0];
    int p = 1;

    while (*ch)
    {
        if (*ch == ',')
        {
            *ch = '\0';
            parts[p++] = ch+1;
        }

        ch++;
    }

    for (p = 0; p < 4; p++) {
        puts(parts[p]);
    }

    return(0);
}

Not very tidy, but should give you an idea of how I'd approach it.

Share this post


Link to post
Share on other sites

Just similar to my version:


Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Share this post


Link to post
Share on other sites

trancexx

Thank you so much, specially for the comments. I'm going to give it a try.

Mat

Thank you, I will give it a try too.

No, that's not always 4 elements, but the first character ('1' in this example) could be used to know how many elements is there.

A value of 1 means there are a total of 4 elements,

A value of 2 = 4 elements

A value of 3 = 3 elements

4 = 4 elements

5 = 3 elements

1 means Login request, 2 means CheckIn request, 3 mean Password Reset request, 4 means Password Change request and 5 means Logout request.

1 = 1,Username,PasswordAsMD5,MachineId

2 = 2,Username,PasswordAsMD5,MachineId

3 = 3,Username,Email

4 = 4,Username,CurrentPasswordAsMD5,NewPassword

5 = 5,Username,MachineId

funkey

Thanks, I will check that thread as soon as I finished with the above codes...

Share this post


Link to post
Share on other sites
char buf[RECV_BUF_LEN] = {}; // zero-ed out

//...the rest of your code that fills the buf...

// Calculate how many chunks of strings are in your buf
int ibound = 0;
for (int i = 0; i < RECV_BUF_LEN; ++i)
{
    if (buf[i] == ',')
    {
        buf[i] = '\0';
        ++ibound;
    }
}

// Now you allocate space for calculated number of (string) pointers
char** szArr = new char*[ibound + 1];

for (int j = 0, i = 0; j <= ibound; ++j)
{
    szArr[j] = &buf[i]; // set this pointer to your array
    for (; i < RECV_BUF_LEN; ++i)
    {
        if (buf[i] == '\0')
        {
            ++i; // skip this one
            if (buf[i] == ' ') ++i; // skip "space" too
            break;
        }
    }
}

// Print elements of your array just because
for (int i = 0; i <= ibound; ++i)
printf("%i. %s\n", i, szArr[i]);

// Free dynamically allocated array (don't forget this)
delete[] szArr;

fflush(stdout); // flush to see what's printed

Clueless here.  Hi.  Sorry to hijack.  Why does szArr need to be a **?  I assume that means an array of pointers to pointers?

Share this post


Link to post
Share on other sites

^^ It means pointer to array of pointers.

You should see AutoIt source. At one place it has Variant***.

1 person likes this

♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

trancexx

Thanks a lot, you were really helpful, as always of course.

Here is what I came up with finally:

LPSTR *StringToCsv(CHAR buf[], int *nBound)
{
    int i = 0, j = 0;

    *nBound = 0;
    while (buf[i] != '\0')
    {
        if (buf[i] == ',')
        {
            buf[i] = '\0';
            *nBound += 1;
        }

        i++;
    }

    *nBound += 1;

    char **szArray = new char *[*nBound];
    for (j = 0, i = 0; j <= *nBound - 1; j++)
    {
        szArray[j] = &buf[i];

        while (buf[i] != '\0')
        {
            i++;

            if (buf[i] == '\0')
            {
                i++;
                break;
            }
        }
    }

    return szArray;
}

Mat, thank you too.

Share this post


Link to post
Share on other sites

#15 ·  Posted (edited)

Ahhhh, pointer to an array of pointers makes a lot more sense.  And I learned something new today.  Yay!  Thx trancexx.

Urm, but what could Variant*** possibly mean?  A pointer to a pointer to a pointer to a type Variant?  Also, what turn of events occurred to even create a spawn?

Edited by jaberwacky

Share this post


Link to post
Share on other sites

#17 ·  Posted (edited)

Oh, Variant*** is a pointer to a container of pointers to variants isn't it?

 

Edit, no, probably not actually.

It's not that hard to imagine what it would be needed for.

If you look at the code posted here char*** could have been used as well to pass pointer to szArr to some function that would do allocation:

void Allocate(char*** xy, int size)
{
    *xy = new char*[size + 1];
}

//...

char** szArr;
Allocate(&szArr, ibound);
But since this is C++, it's more correct to do it like this, if you are doing it that way:

void Allocate(char**& xy, int size)
{
    xy = new char*[size + 1];
}

//...

char** szArr;
Allocate(szArr, ibound);
Edited by trancexx

♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

It's not that hard to imagine what it would be needed for.

Easy for you to say.

I think this seals the deal.  I'll never be ready for prime time when it comes down to c++.

Thanks for taking the time to show me that!  Appreciate it.

Share this post


Link to post
Share on other sites

That C++ code to FlowChart with this site: http://code2flow.com/

it help me to see the overall logic of the above program.

I would love a tool like that (code2flow.com), for the AutoIt language, were included in this site autoitscript.com...

 

YtcG2m.code.png


small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0