Pointer Problem


A

arnuld

WANTED: To print the value of the key.
GOT: Weired printing on screen


Key is the +OK string and its value is separated by a space from it e.g.

+OK HTTP_REQUEST

I have a full sentence which contains many characters (even newlines) and
I want to take out the value of the key from it. Its printing almost a
mess. When I print an array it prints fine but if it is passed to another
function then it prints mess.




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


enum { SIZE_ARR = 50 };

int string_copy_till_newline(char dest[], char src[]);
int get_pointer_for_value_using_key(const char* recv_arr, char* id);


int main(void)
{
char arr_dest[SIZE_ARR+1] = {0};
char arr_src[] = "Content-Type: HTTP/response\nContent-Length: 41\n\n
+OK HTTP_REQUEST_ACCEPTED\n---END\n";


printf("arr_dest = %s\n", arr_dest);
printf("arr_src = %s\n", arr_src);
printf("\n------------------------------\n");

if(get_pointer_for_value_using_key(arr_src, arr_dest))
{
string_copy_till_newline(arr_dest, arr_src);
printf("arr_dest = %s\n", arr_dest);
/* printf("arr_src = %s\n", arr_src);*/
}
else
{
printf("get_pointer_for_value_using_key() returned NULL\n");
}

return 0;
}



int get_pointer_for_value_using_key(const char* recv_arr, char* id)
{
char* p = strstr(recv_arr, "+OK");

if(NULL == p || NULL == id)
{
printf("IN: %s - %d: ONe of the arguments is NULL. This is SERIOUS
ERROR\n", __func__, __LINE__);
printf("p = %p\nid = %p\n", (void*)p, (void*)id);
return 0;
}
else /* Skip first 4 characters (+OK and a space) to read the unique ID
*/
{
p += 4;
printf("p --> %s\n", p);
return string_copy_till_newline(id, p);
}
}


/* Will copy contents from SRC to DEST till a newline occurs, will not
include newline, puts a NULL character at the end.
returns number of characters copied, else -1 on error. Will write
beyond the array, size checking is user's responsibility */
int string_copy_till_newline(char dest[], char src[])
{
int idx;

if(NULL == dest || NULL == src)
{
printf("IN: %s at %d: One of the arguments is NULL\n", __func__,
__LINE__);
return -1;
}

printf("src =%s\n", src);
/*
for(idx = 0; (idx < SIZE_ARR) && src[idx] != '\0' src[idx] != '\n'; +
+idx)
{
printf("src[idx] = %c\n", src[idx]);
dest[idx] = src[idx];
}

dest[idx] = '\0';
*/
return idx;
}


===================== OUTPUT =============================
[[email protected] programs]$ gcc -ansi -pedantic -Wall -Wextra string-play.c
[[email protected] programs]$ ./a.out
arr_dest =
arr_src = Content-Type: HTTP/response
Content-Length: 41

+OK HTTP_REQUEST_ACCEPTED
---END


------------------------------
p --> HTTP_REQUEST_ACCEPTED
---END

src =HTTP_REQUEST_ACCEPTED
---END

src =Content-Type: HTTP/response
Content-Length: 41

+OK HTTP_REQUEST_ACCEPTED
---END

arr_dest =
 
Ad

Advertisements

B

Ben Bacarisse

arnuld said:
WANTED: To print the value of the key.
GOT: Weired printing on screen


Key is the +OK string and its value is separated by a space from it e.g.

+OK HTTP_REQUEST

I have a full sentence which contains many characters (even newlines) and
I want to take out the value of the key from it. Its printing almost a
mess. When I print an array it prints fine but if it is passed to another
function then it prints mess.

You've commented out most of the copy routine and so there is not
predictable data in the array that you print. In fact, the return value
from get_pointer_for_value_using_key is also unpredictable.

I am concerned that posting on Usenet seems like a good way to debug
code like this. Is it not faster to work it out for yourself? Even if
at first it is slower, acquiring the skills to find out what ones code
is doing is surely worth a bit of initial struggle.

<snip>
 
A

arnuld

...SNIP...
I am concerned that posting on Usenet seems like a good way to debug
code like this. Is it not faster to work it out for yourself? Even if
at first it is slower, acquiring the skills to find out what ones code
is doing is surely worth a bit of initial struggle.

I post here because I have learned almost all of the C programming here.
Rules how C works, standards on writing programs, a function' behaviors.
Unfortunately I could not learn in College as my college taught me to use
void main() all the time and they still do. So I search archives, read
different posts and then think and then code.

BTW, I have made it working, pulled 2 functions into 1:



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

enum { SIZE_ARR = 50 };

int get_pointer_for_value_using_key(const char* recv_arr, char* id);


int main(void)
{
char arr_dest[SIZE_ARR+1] = {0};
char arr_src[] = "Content-Type: HTTP/response\nContent-Length: 41\n\n
+OK HTTP_REQUEST_ACCEPTED\n---END\n";


printf("arr_dest = %s\n", arr_dest);
printf("arr_src = %s\n", arr_src);
printf("\n------------------------------\n");

if(get_pointer_for_value_using_key(arr_src, arr_dest))
{
printf("arr_dest = %s\n", arr_dest);
}
else
{
printf("get_pointer_for_value_using_key() returned NULL\n");
}

return 0;
}



int get_pointer_for_value_using_key(const char* recv_arr, char* id)
{
int idx;
char* p = strstr(recv_arr, "+OK");

if(NULL == p || NULL == id)
{
printf("IN: %s - %d: One of the arguments is NULL. This is SERIOUS
ERROR\n", __func__, __LINE__);
printf("p = %p\nid = %p\n", (void*)p, (void*)id);
return 0;
}

p += 4;

for(idx = 0; (idx < SIZE_ARR-1) && p[idx] != '\0' && p[idx] != '\n'; +
+idx)
{
id[idx] = p[idx];
}

id[idx] = '\0';

return idx;
}

===================== OUTPUT =============================
[[email protected] programs]$ gcc -ansi -pedantic -Wall -Wextra string-play.c
[[email protected] programs]$ ./a.out
arr_dest =
arr_src = Content-Type: HTTP/response
Content-Length: 41

+OK HTTP_REQUEST_ACCEPTED
---END
 
A

arnuld

for(idx = 0; idx < SIZE_ARR
&& src[idx] != '\0'
&& src[idx] != '\n'; ++idx)
{
printf("src[idx] = %c\n", src[idx]);
dest[idx] = src[idx];
}
dest[idx] = '\0';


I modifed the idx < SIZE_ARR to idx < SIZE_ARR-1, last slot being kept
for NULL character :)
 
J

Jorgen Grahn

WANTED: To print the value of the key.
GOT: Weired printing on screen


Key is the +OK string and its value is separated by a space from it e.g.

+OK HTTP_REQUEST

I have a full sentence which contains many characters (even newlines) and
I want to take out the value of the key from it.

State your problem more clearly, and you'll see the solution. This
question is, like most other parsing questions on Usenet, muddily
formulated.

I can guess that you mean "if I split my string on whitespace, I want
the first token after the first "+OK" token, assuming these exist" --
but you might mean something completely different.

/Jorgen
 
B

Ben Bacarisse

arnuld said:
BTW, I have made it working, pulled 2 functions into 1:

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

enum { SIZE_ARR = 50 };

int get_pointer_for_value_using_key(const char* recv_arr, char* id);


int main(void)
{
char arr_dest[SIZE_ARR+1] = {0};
char arr_src[] = "Content-Type: HTTP/response\nContent-Length: 41\n\n
+OK HTTP_REQUEST_ACCEPTED\n---END\n";


printf("arr_dest = %s\n", arr_dest);
printf("arr_src = %s\n", arr_src);
printf("\n------------------------------\n");

if(get_pointer_for_value_using_key(arr_src, arr_dest))
{
printf("arr_dest = %s\n", arr_dest);
}
else
{
printf("get_pointer_for_value_using_key() returned NULL\n");
}

return 0;
}



int get_pointer_for_value_using_key(const char* recv_arr, char* id)
{
int idx;
char* p = strstr(recv_arr, "+OK");

Using "+OK " would be better. You add 4 to p later but of the string
ends at the K or the newline comes there, your code will go wrong. This
may never happen, but almost everything can't happen in a piece of
software eventually does.
if(NULL == p || NULL == id)
{
printf("IN: %s - %d: One of the arguments is NULL. This is SERIOUS
ERROR\n", __func__, __LINE__);
printf("p = %p\nid = %p\n", (void*)p, (void*)id);
return 0;
}

p += 4;

for(idx = 0; (idx < SIZE_ARR-1) && p[idx] != '\0' && p[idx] != '\n'; +
+idx)
{

It's a shame to have the array size global line this. A utility
function like that should take the size as an argument.

I'd probably even make the string to look for an argument because you
never know when you might want to look for some other string. You can
the write the on-line call to look specifically for "+OK " if that makes
things neater.
id[idx] = p[idx];
}

id[idx] = '\0';

return idx;
}

<snip>
 
Ad

Advertisements

K

Keith Thompson

arnuld said:
I modifed the idx < SIZE_ARR to idx < SIZE_ARR-1, last slot being kept
for NULL character :)

You mean null character or '\0', not NULL character. NULL is a
macro that expands to a null pointer constant.

The distinction is important. I've seen code that assigns NULL to
an element of a character array (which works if the implementation
happens to have "#define NULL 0").
 
N

Nick Keighley

int get_pointer_for_value_using_key(const char* recv_arr, char* id)
{
  char* p = strstr(recv_arr, "+OK");

  if(NULL == p || NULL == id)
    {
      printf("IN: %s - %d: ONe of the arguments is NULL. This is SERIOUS
ERROR\n", __func__, __LINE__);

this is a lie. If recv_arr is NULL then the program will have crashed
before it gets here.
      printf("p = %p\nid = %p\n", (void*)p, (void*)id);
      return 0;
    }
  else /* Skip first 4 characters (+OK and a space) to read the unique ID
*/
    {
      p += 4;
      printf("p --> %s\n", p);
      return string_copy_till_newline(id, p);
    }

}

int get_pointer_for_value_using_key(const char* recv_arr, char* id)
{
if(NULL == recv_arr || NULL == id)
{
printf("IN: %s - %d: ONe of the arguments is NULL. This is
SERIOUS"
"ERROR\n", __func__, __LINE__);

/* I STILL have reservations about library functions printing error
messages. Have you considered assert()? */

printf("recv_arr = %p\nid = %p\n", (void*)recv_arr ,
(void*)id);
return 0;
}
else /* Skip first 4 characters (+OK and a space) to read the unique
ID
*/
{
char* p = strstr(recv_arr, "+OK"); /* only call strstr()
when we know recv_arr is ok */
p += 4;
printf("p --> %s\n", p);
return string_copy_till_newline(id, p);
}
}

<snip>
 
I

ImpalerCore

this is a lie. If recv_arr is NULL then the program will have crashed
before it gets here.



int get_pointer_for_value_using_key(const char* recv_arr, char* id)
{
  if(NULL == recv_arr || NULL == id)
    {
      printf("IN: %s - %d: ONe of the arguments is NULL. This is
SERIOUS"
              "ERROR\n", __func__, __LINE__);

/* I STILL have reservations about library functions printing error
messages. Have you considered assert()? */

The issue is that there doesn't seem to be a single solution that
satisfies all the criteria that will get acceptance from the community
at large. Once you start throwing in asserts, you get criticism from
the people who subscribe to the defensive programming paradigm
shouting the 'never crash the application' mantra (and for good
reason). In a development or test environment, you want these kinds
of errors to be like a car crash, enough to make the developer sit up
and take note. His version and your 'assert' suggestion is annoying
enough that a developer seeing his message will nudge or force them to
resolve the problem.

When it comes to production phase, and the app is shipped to the user,
all of a sudden the priorities change. Instead of strict adherence to
code correctness, the code should now be robust to user _and_
developer errors. This implies that printing unsightly messages and
crashing the application are no longer acceptable. To handle this
problem, the motivation is to lean on using return values and errno
like states as error conditions that require the
'get_pointer_for_value_using_key' module developer to do extra work to
avoid an ignorant developer or malicious user from doing something bad
with the application.

The drawback of using return codes and other error states is that the
developer has to explicitly check for them, and the average developer
is inconsistent in that regard. Checking errors is complex, which
tends to lead developers to avoid checking them, it's not taught well
in academia (imo), so experience properly handling errors is learned
by grit and spit. So uncaught errors that 'assert' would have fired
on (which would then force the developer to resolve them) will instead
propagate until their behavior is perhaps caught in the testing phase
(costing more resources), or observed in the form of a user's bug
report (costing even more resources), and the behavior observed may be
far from the origin of the defect itself.

From his function definition, the intent appears to be that a NULL
value for 'recv_arr' or 'id' is semantically invalid, and hence a
client that inadvertently calls it with NULL would be considered a
software defect, which ideally would be picked up in the development
or testing phases. (In contrast, a function that takes a semantically
valid NULL pointer could be a pointer to a linked list, where the NULL
pointer represents an empty list.) Unfortunately, testing resources
are limited, people are imperfect, and software is rarely shipped
without 100% confidence that software defects are removed.

So the issue comes down to what role a library function has on error
management, and I don't have a good answer. The most common 'contract
programming' style is to use an assertion, which has its best value in
the development and testing environment. The most common 'defensive
programming' style is to use an early-exit scheme, which has its best
value in a production environment. Manually writing code to one style
seems to negate the advantages of the other.

\code snippet
int get_pointer_for_value_using_key(const char* recv_arr, char* id)
{
assert( recv_arr != NULL );
assert( id != NULL );

...
}
\endcode

Now you compile for production and remove the asserts, and because of
imperfect test coverage, a software defect causes this function to be
passed a NULL argument. You just get an unhappy user that says the
program crashed.

\code snippet
int get_pointer_for_value_using_key(const char* recv_arr, char* id)
{
if ( recv_arr == NULL || id == NULL )
return 0; /* maybe set errno too */

...
}
\endcode

In this scenario, the library function is playing defensive, and
because of imperfect test coverage, a software defect causes this
function to be passed a NULL argument. You may or may not have an
observable side effect, but if this defect eventually causes the user
to see invalid behavior, the point of origin is gone, and the
difficultly of locating the cause of the error can be higher. One
could perhaps discretely log this defect information in a file, or
send defect reports over the web to a server, alerting developers to
defects while still trying to preserve a positive experience for the
user. But again this brings up the question of what role a library
function has in error management.

The advantage of the library taking a proactive role in error
management is that it gives the library designer (who should be the
most knowledgeable person on its implementation and any of its
caveats) the best opportunity to enforce code correctness on its
clients. The main advantage I think is to help the library developer
not have to answer as many "dumb" questions. The disadvantage is that
strict adherence to code correctness is that the library will take
flak for not handling the error the way the developer wants to handle
it (like not wanting library functions to print error messages, or
aborting the program on an allocation failure). There's probably
others, but these are what stick out to me.

There isn't a de facto approach that I've observed to handling this
problem. Standard libraries choke silently on NULL arguments, some
developers love or hate assert, some developers ignore errors unless
it produces a bug report, and some have complex code testing for every
error under the sun. Hence, it's difficult to make everybody happy,
especially when posting code in a group like comp.lang.c.

"You can't please everyone, so you've got to please yourself."

Best regards,
John D.

<snip>
 
Ad

Advertisements

I

ImpalerCore

Unfortunately, testing resources
are limited, people are imperfect, and software is rarely shipped
without 100% confidence that software defects are removed.

should be ...

Unfortunately, testing resources
are limited, people are imperfect, and software is rarely shipped
*with* 100% confidence that software defects are removed.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Top