Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   pointer from integer without a cast (http://www.velocityreviews.com/forums/t951505-pointer-from-integer-without-a-cast.html)

Rudra Banerjee 08-28-2012 09:56 PM

pointer from integer without a cast
 
Dear friends,
I am a C novice. I am trying to get the basename of a file(filename) without extension. The problem is much discussed in net, but due to my limited knowledge, I failed to make fruitful use of them, and thought I may use the unix command, as given.

char myCommand[512];
// char *basetmp=strrchr(filename,'/')+1;
sprintf(myCommand,"basename %s .bib",filename);
char *basefn=system((char *)myCommand);
printf (basefn);
variable filename is defined as char*.
This code is giving warnning:308:18: warning: initialization makes pointer from integer without a cast [enabled by default]
where line no 308 is "char *basefn=system((char *)myCommand);"

If anybody kindly show me where I am getting wrong, or better still, a better(and small) method to get the same function without unix command, it will be of huge help.

Barry Schwarz 08-28-2012 10:13 PM

Re: pointer from integer without a cast
 
On Tue, 28 Aug 2012 14:56:50 -0700 (PDT), Rudra Banerjee
<bnrj.rudra@gmail.com> wrote:

>Dear friends,
>I am a C novice. I am trying to get the basename of a file(filename) without extension. The problem is much discussed in net, but due to my limited knowledge, I failed to make fruitful use of them, and thought I may use the unix command, as given.
>
> char myCommand[512];
>// char *basetmp=strrchr(filename,'/')+1;
> sprintf(myCommand,"basename %s .bib",filename);
> char *basefn=system((char *)myCommand);
> printf (basefn);
>variable filename is defined as char*.
>This code is giving warnning:308:18: warning: initialization makes pointer from integer without a cast [enabled by default]
>where line no 308 is "char *basefn=system((char *)myCommand);"
>
>If anybody kindly show me where I am getting wrong, or better still, a better(and small) method to get the same function without unix command, it will be of huge help.


The C function system() does not return the "output" of the command it
executes. It returns an implementation-defined "status" which has
type int. (Most commands return 0 status to indicate success.)

In this case, the output from basename probably went directly to your
screen. One way for you to get the output, if your system supports
redirection (>>), would be to add " >> basename_output_file.txt" to
your sprintf format string and then open the file and read the output.

By the way, your cast in the call to system() serves no purpose.
myCommand is an array of char. In this context, the expression
myCommand is automatically converted to &myCommand[0] which already
has type char*.

--
Remove del for email

James Kuyper 08-28-2012 10:47 PM

Re: pointer from integer without a cast
 
On 08/28/2012 05:56 PM, Rudra Banerjee wrote:
> Dear friends,
> I am a C novice. I am trying to get the basename of a file(filename) without extension. The problem is much discussed in net, but due to my limited knowledge, I failed to make fruitful use of them, and thought I may use the unix command, as given.
>
> char myCommand[512];
> // char *basetmp=strrchr(filename,'/')+1;
> sprintf(myCommand,"basename %s .bib",filename);
> char *basefn=system((char *)myCommand);
> printf (basefn);
> variable filename is defined as char*.
> This code is giving warnning:308:18: warning: initialization makes pointer from integer without a cast [enabled by default]
> where line no 308 is "char *basefn=system((char *)myCommand);"
>
> If anybody kindly show me where I am getting wrong,


The value returned by system() is an int. Your code tries to implicitly
convert that int to a pointer, which is not permitted, hence the warning
message. Such conversions can only be done explicitly by using a cast.
Inserting (int) before system() would disable the warning message, but
would not solve your problem. The value returned by the system() command
when it is given a non-null pointer argument is an
implementation-defined status code, so converting it to a pointer is
pointless, and could cause your program to crash.

I'm familiar with the basename command as a standard utility available
on unix-like systems like the ones I use at home and at work. I've not
idea whether other systems provide a similar command with the same name.
The rest of this message is specific to my desktop system, and if not
applicable to your system, should be ignored. If the advice is
applicable to your system, any questions should be directed to
comp.programmer.unix, rather than this forum. There are people there who
can give you better answers than I can about such systems.

system() returns "-1 on error (e.g. fork() failed), and the return
status of the command otherwise. This latter return status is in the
format specified in wait(2)." That's not what you want.

What you really want is to capture the string that gets printed out by
the basename command, but capturing that string is a complicated task
that would start with using popen() rather than system(), and gets
steadily more complicated from there. I'd recommend someday learning how
to do that, because someday you might need to, but this isn't that day;
wait until you no longer call yourself a "novice".

You're much better off using the basename() function, rather than
system() and the basename command. Type "man 3 basename" at your command
line for more information.

Lew Pitcher 08-28-2012 11:03 PM

Re: pointer from integer without a cast
 
On Tuesday 28 August 2012 17:56, in comp.lang.c, bnrj.rudra@gmail.com wrote:

> Dear friends,
> I am a C novice. I am trying to get the basename of a file(filename)
> without extension. The problem is much discussed in net, but due to my
> limited knowledge, I failed to make fruitful use of them, and thought I
> may use the unix command, as given.
>
> char myCommand[512];
> // char *basetmp=strrchr(filename,'/')+1;
> sprintf(myCommand,"basename %s .bib",filename);

[snip
> If anybody kindly show me where I am getting wrong, or better still, a
> better(and small) method to get the same function without unix command, it
> will be of huge help.


The POSIX standard defines a C function called basename() that, on Unix-like
platforms, does most of what you want to do. But, as we are discussing your
problem in comp.lang.c, we'll not discuss POSIX functions; they are best
left for discussion in a POSIX, Unix, or Linux newsgroup.

OTOH, if you know the rules for filename (and presumably pathname) creation
on your platform (like, "paths are names separated by slashes", or "a slash
at the rightmost end of the name can be ignored"), and the rules for the
basename utility program (like, the 2nd parameter is a filename suffix),
*you* can write the equivalent processing in standard C.

Working from right to left (from end-of-string to start-of-string)
- delete the trailing slash if present
- delete the file suffix if present
- find the leftmost slash, or start of string

Your filename starts +1 from that leftmost slash (or +0 from the start of
string), and ends just prior to that file suffix you deleted.
This is /easily/ coded in C, without any function calls.

HTH
--
Lew Pitcher
"In Skills, We Trust"

Lew Pitcher 08-28-2012 11:05 PM

Re: pointer from integer without a cast
 
Too quick to post without proofreading

On Tuesday 28 August 2012 19:03, in comp.lang.c, lpitcher@teksavvy.com
wrote:

[snip]
> Working from right to left (from end-of-string to start-of-string)
> - delete the trailing slash if present
> - delete the file suffix if present
> - find the leftmost slash, or start of string


Gaak! Correction
- find the RIGHTMOST slash, or start of string

>

Your filename starts +1 from that RIGHTMOST slash (or +0 from the start of
string), and ends just prior to that file suffix you deleted.
> This is /easily/ coded in C, without any function calls.


--
Lew Pitcher
"In Skills, We Trust"

Ben Bacarisse 08-28-2012 11:14 PM

Re: pointer from integer without a cast
 
Rudra Banerjee <bnrj.rudra@gmail.com> writes:

> Dear friends, I am a C novice. I am trying to get the basename of a
> file(filename) without extension. The problem is much discussed in
> net, but due to my limited knowledge, I failed to make fruitful use of
> them, and thought I may use the unix command, as given.


>
> char myCommand[512];
> // char *basetmp=strrchr(filename,'/')+1;
> sprintf(myCommand,"basename %s .bib",filename);
> char *basefn=system((char *)myCommand);
> printf (basefn);


NOTE: that's dangerous! All hell will break loose if the file name
includes %s for example.

> variable filename is defined as char*.


> This code is giving warnning:308:18: warning: initialization makes
> pointer from integer without a cast [enabled by default] where line no
> 308 is "char *basefn=system((char *)myCommand);"
>
> If anybody kindly show me where I am getting wrong, or better still, a
> better(and small) method to get the same function without unix
> command, it will be of huge help.


For the Unix answer, see if your system has a basename function. To
find out more about it, ask in comp.unix.programmer.

There's a C answer as well, because the problem is just one of
manipulating characters so here is an explanation of a simple way to do
what you want.

You are on the right track with strrchr but exactly what will work for
you depends on what you want to do with the string later and where the
file name came from to start with.

The most flexible method will make a copy of the resulting shortened
file name. The only thing you then need to worry about is freeing the
storage when you no longer need it.

Here are the key parts:

strrchr can find the last / in the name, but it may return NULL if
there was no / to find:

const char *basename = strrchr(filename, '/');
if (basename == NULL)
basename = filename;
else basename += 1; // point to after the '/' just found

strrchr can then also find the . that marks a possible extension.
Again you need to check if there really is one:

const char *end = strrchr(basename, '.');
if (end == NULL)
end = strrchr(basename, 0); // can't fail

If you specifically want to remove only ".bib" it's a little bit more
complicated because you might have a name like "my.bib.file.bib". The
following would work:

const char *end = strchr(basename, 0);
if (strlen(basename) >= 4 && strcmp(end - 4, ".bib") == 0)
end -= 4;

Subtracting two pointers into an array (a string is just an array of
characters) gives you the number of elements between them. To make a
copy of a part of the string, you can use strndup. It's not standard
C, but you don't seem to be looking for a fully standard solution:

return strndup(basename, end - basename);

To avoid strndup, all you need is malloc to get the storage and memcpy
to copy the characters:

char *copy = malloc(end - basename + 1); // +1 for the null we add
if (copy != NULL) {
memcpy(copy, basename, end - basename);
copy[basename - end] = 0;
}
return copy;

The whole thing then needs to be wrapped up into a function for general
use. Something like:

char *get_basename(const char *filename)
{
....
}

Change the name if you choose the version that only removes a trailing
".bib"!

--
Ben.

BartC 08-29-2012 12:18 AM

Re: pointer from integer without a cast
 
Rudra Banerjee" <bnrj.rudra@gmail.com> wrote in message
news:2163629c-1e5f-4b19-a97e-3dc0497b760f@googlegroups.com...
> I am a C novice. I am trying to get the basename of a file(filename)
> without extension. The problem is much discussed in net, but due to my
> limited knowledge, I failed to make fruitful use of them, and thought I
> may use the unix command, as given.


> If anybody kindly show me where I am getting wrong, or better still, a
> better(and small) method to get the same function without unix command, it
> will be of huge help.


I've knocked together some code here. This does a few extra things, I
believe the functionality you want is in 'ExtractBaseFile()', but as
written, these are interdependent.

This code is little peculiar because it uses a 'string slice' type to return
a result; that is a pointer to a string plus a length, rather than just a
pointer to C-terminated string. This makes it possible to point into the
middle of an existing string (and to avoid messing with malloc()). To use
the result conventionally use the MakeCstring() conversion, or just copy the
bytes into a char array, and add a zero..

(I've assumed that filespecs on your machine are like Windows', except with
no "\" or ":" characters.)

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

typedef struct {char* str; int len;}strslice;

/* ------------------------------------ */
strslice MakeSlice(char* str,int len){
strslice s;
s.str=str;
s.len=len;
return s;
}

/* ------------------------------------ */
strslice ExtractPath(char* filespec){
int i,len;
char *p,*q;

len=strlen(filespec);
p=filespec+len-1; /* point to last char */
for (i=len; i>=1; --i)
if (*p--=='/') {
return MakeSlice(filespec,i);
}
return MakeSlice("",0);
}

/* ------------------------------------ */
strslice ExtractFile(char* filespec){
strslice s;
int len;

s=ExtractPath(filespec);
if (s.len==0) return MakeSlice(filespec,strlen(filespec)); /* No path
*/
return MakeSlice(s.str+s.len,strlen(filespec)-s.len);
}

/* ------------------------------------ */
strslice ExtractExt(char* filespec,int period){
/* period=1: return trailing "." (null ext) as "." rather than "" */
strslice s;
char *p;
int i;

s=ExtractFile(filespec);
if (s.len==0) return s;
p=s.str+s.len-1;
for (i=s.len; i>=1; --i)
if (*p--=='.')
if (i==s.len)
return period?MakeSlice(".",1):MakeSlice("",0);
else
return MakeSlice(p+2,s.len-i+1);
return MakeSlice("",0);
}

/* ------------------------------------ */
strslice ExtractBaseFile(char* filespec){
strslice f,e;

f=ExtractFile(filespec);
if (f.len==0) return f;
e=ExtractExt(filespec,0);
f.len-=e.len;
if (*(f.str+f.len-1)=='.') --f.len;
return f;
}

/* ------------------------------------ */
char* MakeCstring(strslice s){
char *p;
p=malloc(s.len+1);
if (p==NULL) return NULL;
if (s.len) memcpy(p,s.str,s.len);
*(p+s.len)=0;
return p;
}

/* ------------------------------------ */
int main (void){
char *teststr="/path1/path2/basefile.ext";
strslice slice;
char *newstr;

printf("Filespec = %s\n",teststr);

slice=ExtractPath(teststr);
printf("Path = \"%.*s\"\n",slice.len,slice.str);

slice=ExtractFile(teststr);
printf("File = \"%.*s\"\n",slice.len,slice.str);

slice=ExtractBaseFile(teststr);
printf("Base = \"%.*s\"\n",slice.len,slice.str);

slice=ExtractExt(teststr,1);
printf("Ext = \"%.*s\"\n",slice.len,slice.str);

newstr=MakeCstring(slice);
printf("Ext'= \"%s\"\n",newstr);
}

--
Bartc


Ben Bacarisse 08-29-2012 02:02 AM

Re: pointer from integer without a cast
 
"BartC" <bc@freeuk.com> writes:
<snip>
> /* ------------------------------------ */
> strslice ExtractPath(char* filespec){
> int i,len;
> char *p,*q;
>
> len=strlen(filespec);
> p=filespec+len-1; /* point to last char */


This is technically UB when filespec has zero length. You can, I think,
just drop the -1 and change *p-- to *--p below:

> for (i=len; i>=1; --i)
> if (*p--=='/') {
> return MakeSlice(filespec,i);
> }
> return MakeSlice("",0);
> }


BTW, is this layout and accident of posting or is it how you like to do
things?

<snip>
--
Ben.

BartC 08-29-2012 10:14 AM

Re: pointer from integer without a cast
 
"Ben Bacarisse" <ben.usenet@bsb.me.uk> wrote in message
news:0.4fc26393937a1b300e06.20120829030201BST.87y5 kyfobq.fsf@bsb.me.uk...
> "BartC" <bc@freeuk.com> writes:
> <snip>
>> /* ------------------------------------ */
>> strslice ExtractPath(char* filespec){
>> int i,len;
>> char *p,*q;
>>
>> len=strlen(filespec);
>> p=filespec+len-1; /* point to last char */

>
> This is technically UB when filespec has zero length.


Just pointing to outside the string, without dereferencing (as that's
protected by the following loop)? If that's a serious consideration, then
there might be a couple of places where that could happen and needs a change
of logic. (The original code this was based on just used indexing.)

>> for (i=len; i>=1; --i)
>> if (*p--=='/') {
>> return MakeSlice(filespec,i);
>> }
>> return MakeSlice("",0);
>> }

>
> BTW, is this layout and accident of posting or is it how you like to do
> things?


I'd like to say it's how I do it late at night just before I go to bed, but
no that's my normal layout, in my original post anyway.

But I see some leading spaces get left out when you try and quote the code,
which is supposed to look like this when you substitute leading "." with
spaces:

strslice ExtractPath(char* filespec){
int i;

for (i=strlen(filespec)-1; i>=0; --i)
..if (filespec[i]=='/')
...return MakeSlice(filespec,i+1);
return MakeSlice("",0);
}

(I've also changed this function to avoid the UB ... and the extraneous
braces.)

--
Bartc


James Kuyper 08-29-2012 11:53 AM

Re: pointer from integer without a cast
 
On 08/29/2012 06:14 AM, BartC wrote:
> "Ben Bacarisse" <ben.usenet@bsb.me.uk> wrote in message
> news:0.4fc26393937a1b300e06.20120829030201BST.87y5 kyfobq.fsf@bsb.me.uk...
>> "BartC" <bc@freeuk.com> writes:
>> <snip>
>>> /* ------------------------------------ */
>>> strslice ExtractPath(char* filespec){
>>> int i,len;
>>> char *p,*q;
>>>
>>> len=strlen(filespec);
>>> p=filespec+len-1; /* point to last char */

>>
>> This is technically UB when filespec has zero length.

>
> Just pointing to outside the string, without dereferencing (as that's
> protected by the following loop)?


Yes. You can increment a pointer one past the end of an array with
defined behavior, but not two past the end, and you can't decrement it
to any position before the beginning of the array (6.5.6p8). The
asymmetry of these rules reflects the fact that some very common loop
idioms require incrementing past the end of an array, but no common
idiom requires going past the beginning.

These idioms became commonplace before the restrictions were imposed, so
this is not an example of circular logic (e.g.: it was disallowed
because no one was using it - no one was using it because it wasn't
allowed).

<pedantic>Technically, the standard only endorses end_of_array+1 as a
permitted pointer value. It doesn't cover (end_of_array-1)+2. Some
people have argued that (end_of_array-1)+2 is necessarily equal to
end_of_array+1, but to "prove" that identity they assume the associative
property (a+b)+c == a + (b+c). That property can be proven to be true
based upon 6.5.6p8 when 'a' is a pointer type, but only for the cases
where a, a+b, and (a+b)+c all point within the same array; the proof
cannot be validly extended to include pointers one past the end of the
array.</pedantic>
--
James Kuyper


All times are GMT. The time now is 10:49 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.