473,776 Members | 1,505 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Help with type returned

Hi, I need help with this program. The program is supposed to take a
text file and identify the words in it, then it should print them and
count how many times a word is repeated. At first main called the
function wordcount, and then the function did everything including
printing out the results. That worked. Now I want to make the function
return an array of pointers to struct palabra so the calling function
can manage the data as it pleases. What I`m having trouble with, is to
make the function return a pointer to the array of pointers. I`m using
Dev-C++ compiler and the error says "return from incompatible pointer
type" in the line "return pal;" at the end of the function. I tried a
hundred things but nothing seems to work, if it`s not the same error
it`s "conversion to non-scalar type requested" on the same line. Any
help, as well as tips to make the programa better is welcome and
appreciated.

CODE:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUL '\0'

struct palabra
{
char letras[20];
short veces;
};

typedef struct palabra spal;

spal *wordcount(FILE *archivo)
{
char chr, str[20];
struct palabra *pal[1000];
signed short i=0, j=0, k=0, p=0;

for (j = 0; j<20; ++j) str[j] = (char) NUL;

for (i = 0; ; ++i)
{
chr = fgetc(archivo);
switch (chr)
{
case '.':
str[i] = (char) NUL;
i = -1;
break;

case ',':
str[i] = (char) NUL;
i = -1;
break;

case ':':
str[i] = (char) NUL;
i = -1;
break;

case ' ':
str[i] = (char) NUL;
i = -1;
break;

case ';':
str[i] = (char) NUL;
i = -1;
break;

case '!':
str[i] = (char) NUL;
i = -1;
break;

case '?':
str[i] = (char) NUL;
i = -1;
break;

case (char) NUL:
str[i] = (char) NUL;
i = -1;
break;

case EOF:
str[i] = (char) NUL;
i = -1;
break;

default:
str[i] = chr;
break;
}
if (i == -1)
{
if (str[0] != (char) NUL)
{
if (p==0)
{
pal[p] = malloc(sizeof(s pal));
pal[p]->veces = 1;
for (j = 0; j<20; ++j) pal[p]->letras[j] =
(char) NUL;
for (j = 0; str[j] != (char) NUL; ++j)
{
pal[p]->letras[j] = str[j];
}
if (p == 1000) printf("El archivo contiene mas
de mil palabras !!!");
++p;
}
else
{
k=0;
for (j = 0; j<p; ++j)
{
if ((strcmp(str, pal[j]->letras)) == 0)
{
++pal[j]->veces;
++k;
}
}
if (k == 0)
{

pal[p] = malloc(sizeof(s pal));
pal[p]->veces = 1;
for (j = 0; j<20; ++j) pal[p]->letras[j] =
(char) NUL;
for (j = 0; str[j] != (char) NUL; ++j)
{
pal[p]->letras[j] = str[j];
}
++p;
}
}
for (j = 0; j<= 20; ++j) str[j] = (char) NUL;
}
}
if (chr == EOF) break;
}

if (p==0)
{
printf("El archivo no contiene ninguna palabra\n");
return NULL;
}
else
{
return pal;
/* for (i = 0; i<p; ++i)
{
printf("%s, Veces: %d\n", pal[i]->letras, pal[i]->veces);
}*/
}
}

int main(int argc, char *argv[])
{
FILE *texto;
struct palabra *pal[1000];
short i;

/* if ((texto = fopen("prueba.t xt", "w+")) == NULL)
{
printf("Error tratando de abrir el archivo\n");
system("PAUSE") ;
exit(1);
}

fputs ("Hello World", texto);

if ((fclose(texto) ) != 0) printf("No se pudo cerrar correctamente el
archivo\n");*/

if ((texto = fopen("prueba.t xt", "r")) == NULL)
{
printf("Error tratando de abrir el archivo\n");
system("PAUSE") ;
exit(1);
}

if ((pal = wordcount(texto )) == NULL)
{
printf("La operacion fallo\n");
system("PAUSE") ;
exit(1);
}

for (i = 0; pal[i]->letras[0] != NUL; ++i)
{
printf("%s, Veces: %d\n", pal[i]->letras, pal[i]->veces);
}

if ((fclose(texto) ) != NULL) printf("No se pudo cerrar correctamente
el archivo\n");

system("PAUSE") ;
return 0;
}

Dec 9 '05 #1
2 1816
In article <11************ **********@g44g 2000cwa.googleg roups.com>,
<le*****@gmail. com> wrote:
Hi, I need help with this program. Now I want to make the function
return an array of pointers to struct palabra so the calling function
can manage the data as it pleases. What I`m having trouble with, is to
make the function return a pointer to the array of pointers. I`m using
Dev-C++ compiler and the error says "return from incompatible pointer
type" in the line "return pal;" at the end of the function. struct palabra
{
char letras[20];
short veces;
};
Okay, that's the structure itself.

typedef struct palabra spal;
That's an alias for the structure. Incidently, you could have done that
in one step, via

typedef struct palabra { char letras[20]; short veces; } spal;

spal *wordcount(FILE *archivo)
Since spal is an alias for the struct, spal * means a pointer to one
structure, technically, but because of pointer arithmetic, spal *
also stand in for a pointer to the first element of an array of
the structures.
{
char chr, str[20];
struct palabra *pal[1000];
struct palabra has been aliased with spal, so this line could have
also been written as

spal *pal[1000];

That's an array of 1000 pointers to structures.
if (p==0)
{
pal[p] = malloc(sizeof(s pal));
Okay, that's consistant, malloc returns a pointer to a block
of the appropriate size, so effectively the right hand side of that
line has type *spal; you are then storing that pointer into
an array element that is properly typed to hold such pointers.
pal[p]->veces = 1;
That's consistant too.
pal[p]->letras[j] = str[j];
And that is consistant as well.
pal[p] = malloc(sizeof(s pal));
pal[p]->veces = 1;
Those are fine as well.
pal[p]->letras[j] = str[j];
The types there are fine too.
else
{
return pal;
But look at that. pal is an automatic variable which is an array,
each of whose elements is a pointer to a structure. In that
context (and -most- other contexts), a reference to the array name
will automatically be converted to the first element of the
array. Thus, pal will, in that context, devolve into a pointer
to what the first element is, and the first element is a pointer
to a structure, so pal is a pointer to a pointer to a structure.
But your return type is pointer to structure, not pointer to pointer
to structure, so the compiler is complaining.

Even if you got the type right, you would have problems, because you
would be trying to return a pointer to an automatic variable to
outside the scope that the variable exists in.

int main(int argc, char *argv[])
{ struct palabra *pal[1000];
This is the same declaration as for pal in the subroutine, so
this gets you a variable named pal which is a real array
(that is, memory allocated for it) of 1000 elements long,
each of which is a pointer to a structure.
if ((pal = wordcount(texto )) == NULL)
But there you try to assign a value to pal . You can't do that,
because pal is not a pointer: it is an array. Effectively,
the name of an array is something that is a constant value as
far as that scope is concerned.
for (i = 0; pal[i]->letras[0] != NUL; ++i)


Looking at that, it looks like you really do want pal to
come out as a something that could dereferrenced to be
a pointer to a structure, rather than wanting pal to be
an array of structures. That is consistant with everything
in your subroutine except the return value you declared for
the subroutine.
I would suggest to you that unless you have reason otherwise,
that the easiest way to fix your program would be to declare
pal in your main program, and then pass it in as a parameter
to your subroutine, which would write into it, with the
subroutine not trying to return a pointer to anything.
A few other remarks:

- If your program happens to fill in -exactly- 1000 words,
pal[0] through pal[999], then there will be no entries for
which pal[p]->letras[0] is NUL, so you would run off the
end of the array.

- pal[p] does not get anything written into it unless there
is a word to go there, but if there is a word to go there
then pal[p]->letras[0] is not going to be NUL. When
in the main program after you have examined the last entry
you created, you are going to increment p and try to look
at pal[p]->letras but pal[p] is not going to have been assigned
any value. You will probably crash at that point, if you are lucky.

- Your cases can all be compacted into just two cases:

case ':': case ';': case '!': (and so on)
str[i] = (char) NUL;
i = -1;
break;

default:
str[i] = chr;
break;
You can have many different "case" prefixes for the same block of code.

- I would suggest that you consider replacing your switch() with a
test such as

if ( isalpha(chr) ) { str[i] = (char) NUL; break }
str[i] = chr;

You will have to decide what you want to do with numbers and characters
such as @ . I would suggest to you that you probably do not want
to consider characters such () to be part of a word (otherwise when
you analyzed this sentance, you would end up with a word "(otherwise "
complete with the "(" and that would be a different word than
"otherwise" (which would be stored complete with quotation marks)
and your matches would be different than they otherwise would...)
--
"law -- it's a commodity"
-- Andrew Ryan (The Globe and Mail, 2005/11/26)
Dec 9 '05 #2
Walter Roberson wrote:
In article <11************ **********@g44g 2000cwa.googleg roups.com>,
<le*****@gmail. com> wrote:
Hi, I need help with this program.

Now I want to make the function
return an array of pointers to struct palabra so the calling function
can manage the data as it pleases. What I`m having trouble with, is to
make the function return a pointer to the array of pointers. I`m using
Dev-C++ compiler and the error says "return from incompatible pointer
type" in the line "return pal;" at the end of the function.

struct palabra
{
char letras[20];
short veces;
};


Okay, that's the structure itself.

typedef struct palabra spal;


That's an alias for the structure. Incidently, you could have done that
in one step, via

typedef struct palabra { char letras[20]; short veces; } spal;

spal *wordcount(FILE *archivo)


Since spal is an alias for the struct, spal * means a pointer to one
structure, technically, but because of pointer arithmetic, spal *
also stand in for a pointer to the first element of an array of
the structures.
{
char chr, str[20];
struct palabra *pal[1000];


struct palabra has been aliased with spal, so this line could have
also been written as

spal *pal[1000];

That's an array of 1000 pointers to structures.
if (p==0)
{
pal[p] = malloc(sizeof(s pal));


Okay, that's consistant, malloc returns a pointer to a block
of the appropriate size, so effectively the right hand side of that
line has type *spal; you are then storing that pointer into
an array element that is properly typed to hold such pointers.
pal[p]->veces = 1;


That's consistant too.
pal[p]->letras[j] = str[j];


And that is consistant as well.
pal[p] = malloc(sizeof(s pal));
pal[p]->veces = 1;


Those are fine as well.
pal[p]->letras[j] = str[j];


The types there are fine too.
else
{
return pal;


But look at that. pal is an automatic variable which is an array,
each of whose elements is a pointer to a structure. In that
context (and -most- other contexts), a reference to the array name
will automatically be converted to the first element of the
array. Thus, pal will, in that context, devolve into a pointer
to what the first element is, and the first element is a pointer
to a structure, so pal is a pointer to a pointer to a structure.
But your return type is pointer to structure, not pointer to pointer
to structure, so the compiler is complaining.

Even if you got the type right, you would have problems, because you
would be trying to return a pointer to an automatic variable to
outside the scope that the variable exists in.

int main(int argc, char *argv[])
{

struct palabra *pal[1000];


This is the same declaration as for pal in the subroutine, so
this gets you a variable named pal which is a real array
(that is, memory allocated for it) of 1000 elements long,
each of which is a pointer to a structure.
if ((pal = wordcount(texto )) == NULL)


But there you try to assign a value to pal . You can't do that,
because pal is not a pointer: it is an array. Effectively,
the name of an array is something that is a constant value as
far as that scope is concerned.
for (i = 0; pal[i]->letras[0] != NUL; ++i)


Looking at that, it looks like you really do want pal to
come out as a something that could dereferrenced to be
a pointer to a structure, rather than wanting pal to be
an array of structures. That is consistant with everything
in your subroutine except the return value you declared for
the subroutine.
I would suggest to you that unless you have reason otherwise,
that the easiest way to fix your program would be to declare
pal in your main program, and then pass it in as a parameter
to your subroutine, which would write into it, with the
subroutine not trying to return a pointer to anything.
A few other remarks:

- If your program happens to fill in -exactly- 1000 words,
pal[0] through pal[999], then there will be no entries for
which pal[p]->letras[0] is NUL, so you would run off the
end of the array.

- pal[p] does not get anything written into it unless there
is a word to go there, but if there is a word to go there
then pal[p]->letras[0] is not going to be NUL. When
in the main program after you have examined the last entry
you created, you are going to increment p and try to look
at pal[p]->letras but pal[p] is not going to have been assigned
any value. You will probably crash at that point, if you are lucky.

- Your cases can all be compacted into just two cases:

case ':': case ';': case '!': (and so on)
str[i] = (char) NUL;
i = -1;
break;

default:
str[i] = chr;
break;
You can have many different "case" prefixes for the same block of code.

- I would suggest that you consider replacing your switch() with a
test such as

if ( isalpha(chr) ) { str[i] = (char) NUL; break }
str[i] = chr;

You will have to decide what you want to do with numbers and characters
such as @ . I would suggest to you that you probably do not want
to consider characters such () to be part of a word (otherwise when
you analyzed this sentance, you would end up with a word "(otherwise "
complete with the "(" and that would be a different word than
"otherwise" (which would be stored complete with quotation marks)
and your matches would be different than they otherwise would...)
--
"law -- it's a commodity"
-- Andrew Ryan (The Globe and Mail, 2005/11/26)


Hi, first of all, thanks for the response.

I have addressed every one of your suggestions. The result, or at least
the partial result is this new program:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUL '\0'

typedef struct palabra
{
char letras[20];
short veces;
} spal;

spal **wordcount(FIL E *archivo, spal **pal)
{
char chr, str[20];
signed short i=0, j=0, k=0, p=0;

for (j = 0; j<20; ++j) str[j] = (char) NUL;

for (i = 0; ; ++i)
{
chr = fgetc(archivo);

if ( !isalpha(chr) )
{
str[i] = (char) NUL;
i = -1;
}
else str[i] = chr;

if (i == -1)
{
if (str[0] != (char) NUL)
{
++p;
for (j = 0; j<= 20; ++j) str[j] = (char) NUL;
}
}
if (chr == EOF) break;
}

if (p==0)
{
printf("El archivo no contiene ninguna palabra\n");
return NUL;
}

rewind (archivo);

if ((pal = malloc ((sizeof(spal **)) * (p+1))) == NULL) return
NUL;

p=0;

for (i = 0; i<20 ; ++i)
{
chr = fgetc(archivo);

if ( !isalpha(chr) )
{
str[i] = (char) NUL;
i = -1;
}
else str[i] = chr;

if (i == -1)
{
if (str[0] != (char) NUL)
{
if (p == 0)
{
if ((pal[0] = malloc(sizeof(s pal))) == NULL)
return NUL;
pal[0]->veces = 1;
for (j = 0; j<20; ++j) pal[0]->letras[j] =
(char) NUL;

for (j = 0; str[j] != (char) NUL; ++j)
{
pal[0]->letras[j] = str[j];
}
++p;
}
else
{
k=0;
for (j = 0; j<p; ++j)
{
if ((strcmp(str, pal[j]->letras)) == 0)
{
++pal[j]->veces;
++k;
}
}
if (k == 0)
{
if ((pal[p] = malloc(sizeof(s pal))) == NULL)
return NUL;
pal[p]->veces = 1;
for (j = 0; j<20; ++j) pal[p]->letras[j] =
(char) NUL;

for (j = 0; str[j] != (char) NUL; ++j)
{
pal[p]->letras[j] = str[j];
}
++p;
}

}
}
for (j = 0; j<= 20; ++j) str[j] = (char) NUL;
}
if (chr == EOF) break;
}
if (i >= 20) return NUL;

if ((pal[p] = malloc(sizeof(s pal))) == NULL) return NUL;
for (j = 0; j<20; ++j) pal[p]->letras[j] = (char) NUL;

/* for (i = 0; pal[i]->letras[0] != NUL; ++i)
{
printf("%s, Veces: %d\n", pal[i]->letras,
pal[i]->veces);
}*/

return pal;
}

int main(int argc, char *argv[])
{
FILE *texto;
spal **pal;
short i;

/* if ((texto = fopen("prueba.t xt", "w+")) == NULL)
{
printf("Error tratando de abrir el archivo\n");
system("PAUSE") ;
exit(1);
}

fputs ("Hello World", texto);

if ((fclose(texto) ) != 0) printf("No se pudo cerrar correctamente el
archivo\n");*/

if ((texto = fopen("prueba.t xt", "r")) == NULL)
{
printf("Error tratando de abrir el archivo\n");
system("PAUSE") ;
exit(1);
}

if ((pal = wordcount(texto , pal)) == NUL)
{
printf("La operacion fallo\n");
system("PAUSE") ;
exit(1);
}

for (i = 0; pal[i]->letras[0] != NUL; ++i)
{
printf("%-20s, Veces: %d, i=%d\n", pal[i]->letras,
pal[i]->veces, i);
}

if ((fclose(texto) ) != NULL) printf("No se pudo cerrar correctamente
el archivo\n");

system("PAUSE") ;
return 0;
}

I have rearranged everything so that:
-First the program counts the number of words in the text file
(repeated ones are included in the count). This way I can dynamically
create an array with the number of words in the text file instead of
just predefining a maximum number of words.
-With that number it then allocates space for p number of pointers to
spal and then assigns the start of this "array" to pal. The space of
the repeated words pointers is wasted, but I preferred to do that than
to check for repeated words during the count.
-Then it proceeds to do the same thing as before, search for new words,
allocate new spals and store the words as strings in them.
-Finally it sets the last string to be always NUL filled and returns
the pointer to the array of pointers to the calling function.

With the last program you made me realize that returning a pointer to
the start of an array that has been created in the called function is
pointless, because the array gets destroyed when the function returns
(I think that's what you meant by automatic variable). So I decided to
use malloc to create the array, I figured that the array would exist as
long as it is not freed or the program exits.

I tried to do what you said about passing a pointer to the function and
then let the function modify it so that it doesn´t need to return it,
but I have failed doing so. I don´t know how the type should be
defined so that happens, all I get is the compiler complaining.

Thanks for letting me know about the function isalpha, I`m new to C,
and I don´t know many functions. The function worked perfectly and it
excludes @ and () already.

Somehow I`m having trouble returning a NULL pointer, I read a FAQ about
it, and concluded that if I use NULL with pointers there should be no
problems, but the compiler proves otherwise. I used NUL instead.

Finally I would like to now if the program is fair enough, i.e. I want
to know if it could be optimized or if I did something that didn´t
need doing.

Dec 10 '05 #3

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
3478
by: abcd | last post by:
kutthaense Secretary Djetvedehald H. Rumsfeld legai predicted eventual vicmadhlary in Iraq mariyu Afghmadhlaistmadhla, kaani jetvedehly after "a ljetvedehg, hard slog," mariyu vede legai pressed Pentagjetvedeh karuvificials madhla reachathe strategy in karkun campaign deshatinst terrorism. "mudivae maretu winning or losing karkun global varti jetvedeh terror?" Mr. Rumsfeld adugued in a recent memormariyuum. vede velli jetvedeh madhla...
2
2043
by: dinks | last post by:
Hi, I'm new to C++ and have been assigned a task which i dont completely understand. Any help would be greately appreciated. Here is the problem: The class "linkedListType" use the "assert" facility. I am to get rid of them and replace them with exceptions. I need to create a "linkedListException" class that's declared and implemented in my "linkedListType" class. This class needs to inherit from the base "exception" class and return...
7
2393
by: Alan Bashy | last post by:
Please, guys, In need help with this. It is due in the next week. Please, help me to implement the functions in this programm especially the first three constructor. I need them guys. Please, help me. This was inspired by Exercise 7 and Programming Problem 8 in Chapter 3 of our text. I have done Exercise 7 for you: Below you will find the ADT specification for a string of characters. It represents slightly more that a minimal string...
8
5481
by: baustin75 | last post by:
Posted: Mon Oct 03, 2005 1:41 pm Post subject: cannot mail() in ie only when debugging in php designer 2005 -------------------------------------------------------------------------------- Hello, I have a very simple problem but cannot seem to figure it out. I have a very simple php script that sends a test email to myself. When I debug it in PHP designer, it works with no problems, I get the test email. If
2
17760
by: Amanda | last post by:
From a guy in Microsoft newsgroups: | In *comp.databases.ibm-db2* there are always IBM guys | from the Toronto labs on line.Post with the | -for the love of god please help- | line and I'm sure you'll get their attention. | Their usually very good:) So here's my transplanted post ==========================================
9
4356
by: Dom Boyce | last post by:
Hi First up, I am using MS Access 2002. I have a database which records analyst rating changes for a list of companies on a daily basis. Unfortunately, the database has been set up (by my predecessor, I hasten to add) so that each day it creates a copy of the record for each company, changes the date to today's date, and prompts the user for any changes of ratings on that day. The resulting data table grows by approx 600 records per...
2
1598
by: duncanblacksmithmath | last post by:
I know a lot of you have seen this before but I have worked on the program and have gotten it to work thus far but I need help getting these two functions to work and implementing them. Here is what I have been trying to work out for these functions but can't get them to fully work out for me. information: A function to access an element of a list by its index called access i(LL, i). It traverses the list LL and returns the address of...
1
3721
by: Rahul | last post by:
Hi Everybody I have some problem in my script. please help me. This is script file. I have one *.inq file. I want run this script in XML files. But this script errors shows . If u want i am attach this script files and inq files. I cant understand this error. Please suggest me. You can talk with my yahoo id b_sahoo1@yahoo.com. Now i am online. Plz....Plz..Plz...
1
2420
gauravgmbhr
by: gauravgmbhr | last post by:
ERROR: returned record type does not match expected record type HI friends what does this error means M not able to figure out
1
2797
by: Webstorm | last post by:
Hi, I hope someone can help me sort this out a bit, Im completely lost. Here is the page I am working on: http://www.knzbusinessbrokers.com/default.asp I have 3 search critera that I need to use when querying the database. Right now it is only looking for a match on one of those dropdowns and not all 3. can anyone help? Here is the code: <form BOTID="0" METHOD="POST" action="businessforsale_interface/Results/test3.asp">
0
10289
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10120
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
9923
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8952
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7471
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6722
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5493
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
3622
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2860
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.