Use pointer math instead of array indexing - c

I'm trying to solve a problem found on my C programming book.
#include <stdio.h>
char *f (char s[], char t[], char out[]);
int main(void)
{
char s[] = "ISBN-978-8884981431";
char t[] = "ISBN-978-8863720181";
char out[10];
printf ("%s\n", f(s,t,out));
return 0;
}
char *f (char s[], char t[], char out[]) {
int i;
for (i=0; s[i] == t[i]; i++)
out[i] = s[i];
out[i] = '\0';
return &out[0];
}
As you can see from the code, this code uses as return value &out[0]: does this means that the complete array is used as return value?
char *f (char s[], char t[], char out[]);
int main(void)
{
char s[] = "ISBN-978-8884981431";
char t[] = "ISBN-978-8863720181";
char out[10];
printf ("%s\n", f(s,t,out));
return 0;
}
char *f (char s[], char t[], char out[]) {
for (; *(s+=1) == *(t+=1);)
*(out+=1) = *s;
*(out+1) = '\0';
return out;
}
This is my proposed solution, but while the proposed code returns "ISBN-978-88", mine only returns "8".
The array is smaller than the lenght of the string, how the proposed code can work without any kind of overflow?
Thanks for your responses.

Your code is too aggressive on side effects: the += 1 operation (which is more commonly denoted simply as ++) should be applied after the copy to the output has been made, not after the comparison.
In addition, you need to save the value of the out buffer before incrementing the pointer, so that you could return a pointer to the beginning of the copied string.
char *orig = out;
for ( ; *s == *t ; s++, t++)
*out++ = *s;
*out = '\0';
return orig;
Demo on ideone.

Your code is returning a pointer to the end of the out array. Not the start. You need to stash the initial value of out and return that.
As an aside, the fact that you can do assignments inside a comparison doesn't mean it's a good idea. That code is going to be very hard to maintain.

&out[0] is equivalent to out. Since arrays in C are passed by reference, in a sense, yes it does return the entire array.
Your solution only prints "8" because you're returning a pointer into the middle of the array. When it tries to print the string, it has no way of knowing that it's in the middle of the array/string, thus you only get a substring printed.

Related

define function with pointer input

I don't fully understand how to work with pointers.
Inside the function is where I need to write code to return the length of input string.
int mystrlen (const char *s)
{
char *s[1000], i;
for(i = 0; s[i] != '\0'; ++i);
printf("Length of string: %d, i");
return 0;
}
Could you tell me how to make it work?
Thank you!!
Remove char *s[1000], declare int i instead of char i, and return i rather than 0:
You need to remove the s inside the function body because it is "shadowing the variable" s that is a function parameter, meaning the s function parameter cannot be read at all.
Changing char i to int i will likely increase the range of possible values to return. If you pass a string with 128 characters in it, char i would result in returning -128 if it is a signed 8-bit type. int is guaranteed to be 16-bit, allowing for strings up to 32767 characters (more than enough for most common uses of a string length function).
You return i because otherwise the function is pointless; even if you print the value, you'd need a way to use the string length, and you can't do that if you don't return it from the function.
Corrected code with example:
#include <stdio.h>
int mystrlen(const char *s)
{
int i;
for (i = 0; s[i] != '\0'; ++i);
return i;
}
int main(void)
{
const char *s = "Hello world!";
int len = mystrlen(s);
printf("Length of string: %d\n", len);
return 0;
}
First of all, using pointers, as the number says, consist in using a reference instead of the actual variable, so if you pass a reference by parameter, you are not passing the actual value of it, just an address to it!
The correct code is:
#include <stdio.h>
int mystrlen (const char *s)
{
int i;
for( i = 0; s[i] != '\0'; ++i);
printf("Length of string: %d\n", i);
return 0;
}
void main(){
char *string = "Hello World";
mystrlen(string);
}
Another thing to point out is that you're trying to declare a const variable and change it. When you declare a const variable it should not change.

simple strcat implementation with pointers

so I was practicing writing c code with pointers using the K&R. For one problem with strcat function, I couldn't find out what was wrong with my code, which according to Visual Studio, returned the destination string unchanged after the strcat function. Any suggestion is appreciated!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int strcat(char* s, char* t);
int main(void)
{
char *s="hello ", *t="world";
strcat(s,t);
printf("%s",s);
return 0;
}
int strcat(char* s,char* t)
{
int i;
i=strlen(s)+strlen(t);
s=(char*) malloc(i);
while(*s!='\0')
s++;
while('\0'!=(*s++=*t++))
;
return 0;
}
I'm pretty sure that strcat returns a char* in the real implementation (holding the original value of the first string).
strcat is not supposed to alter the first parameter's address, so you shouldn't call malloc.
Point #2 means that you need to declare char *s as char s[20] in main (where 20 is some arbitrary number big enough to hold the whole string).
If you really want to alter the value of the an input parameter you will need to pass the address of the value - so it would need to be strcat(char **s, ...) in the function declaration/definition, and called with strcat(&s, ...) in main.
1) defining string in this way
char *s="hello "
means that you are defined a literal string. a literal string is saved into read only memory so you can not edit it
you have to define your string as a char array in order to be able to edit it
char s[100] = "hello ";
2) when you define your function in this way
int strcat(char* s,char* t)
you can not change the address of s into the function strcat(). So assigning memory with malloc() into the function will not change the s address when leaving the function
3) change your function strcat to
int strcat(char** s,char* t)
{
int i;
char *u, *v;
i=strlen(*s)+strlen(t);
v = *s;
u=(char*) malloc(i+1);
while(*v!='\0')
*u++ = *v++;
while('\0'!=(*u++=*t++));
*s = u;
return 0;
}
and you call it in the main with:
char *s="hello ", *t="world";
strcat(&s,t);
In
strcat(char* s, char* t)
the 's' is send by value. The value of 's' at call time is copied into the stack then strcat() is call. At the return of strcat the modified version is discard from the stack. So the calling value of 's' is never changed (and you create a memory leak).
Beward, in C every memory cell can be change, even parameters or instructions sections; some changes can be very hard to understand.
Since you are trying to do like the real strcat it's said that the first parameter
The string s1 must have sufficient space to hold the result.
so you don't need to use malloc
char *strcat(char* s, const char* t);
int main(void)
{
char s[15] = {0}; //
char *t = "world"; //const char * so you can't change it
strcpy(s, "Hello ");
strcat(s,t);
printf("%s\n",s);
return (0);
}
char *strcat(char* s, const char* t)
{
int i = 0;
while (s[i] != '\0')
i++;
while (*t != '\0')
s[i++] = *t++;
s[i] = '\0'; //useless because already initialized with 0
return (s);
}
#include<stdio.h>
#include<string.h>
#define LIMIT 100
void strcatt(char*,char*);
main()
{
int i=0;
char s[LIMIT];
char t[LIMIT];
strcpy(s,"hello");
strcpy(t,"world");
strcatt(s,t);
printf("%s",s);
getch();
}
void strcatt(char *s,char *t)
{
while(*s!='\0')
{
s++;
}
*s=' ';
++s;
while(*t!='\0')
{
*s=*t;
s++;
t++;
}
*s=*t;
}
Dear user,
you don't have to complicate things that much. The simpliest code for strcat, using pointers:
void strcat(char *s, char *t) {
while(*s++); /*This will point after the '\0' */
--s; /*So we decrement the pointer to point to '\0' */
while(*s++ = *t++); /*This will copy the '\0' from *t also */
}
Although, this won't give you report about the concatenation's success.
Look at this main() part for the rest of the answer:
int main() {
char s[60] = "Hello ";
char *t = "world!";
strcat(s, t);
printf("%s\n", s);
return 0;
}
The s[60] part is very important, because you can't concatenate an another string to it's end if it doesn't have enough space for that.

Returning arrays and pointers in C?

I'm relatively a beginner in programming in C and am getting super confused with arrays and pointers.
Basically what I'm trying to do is extend a string that contains binary to the designated length len; (i.e. len=8 for num[]=101 would produce "00000101").
Can someone help me understand what's wrong with this?
const char * extendBinary(char num[], int len) {
char *number = &num;
int length = len;
int difference;
if(strlen(*num)<len) {
difference = len-strlen(num);
while(difference>0)
{
&number = strcat("0", &number);
difference--;
}
}
return number;
}
Your problems start with your specification. If I understand you correctly, you want to have a function where you pass an array of characters and a length. The size of your array of input characters will be between 1 and len? However, your function has no way of knowing what the size of your array num is. If you wanted this to work, you would need to define your function as
const char * extendBinary(char *num, size_t num_len, int len);
so that your function doesn't overrun your buffer pointed to by num. Note that I replaced char num[] with char *num as this is the common mechanism for passing a pointer. You cant pass pointers to arrays and then dereference that pointer and get back the original type (that includes its size) -- that's just one thing that C doesn't let you do, so just use a normal pointer and a separate size variable.
Finally, you'll have to deal with memory allocation unless you want a memory leak. Thus, you could simply say that whom ever calls extendBinary should free it's return value when done with it.
const char * extendBinary(char *num, size_t num_len, int len) {
char *ret = malloc(len + 1);
int i;
memset(ret, '0', len);
ret[len] = 0;
strncpy(&ret[len - num_len], num, num_len);
return ret;
}
int main(void) {
char arr[] = {'1', '0', '1'};
const char *formatted = extendBinary(arr, sizeof(arr), 8);
printf("%s\n", formatted);
free(formatted);
return 0;
}
this is wrong.
strcat("0", &number);
A weird way to fix you code would be this:
char temp[32] = {};
...
...
while(difference>0)
{
strncat(temp, "0", 31 - strlen(temp));
difference--;
}
strncat(temp, num, 31 - strlen(temp));
strncpy(num, temp, len);
Note, I am writing this code just to help you understand how strcat() works, there is much better ways to do what you are trying to do.
You cannot concatenate something to a const string, you must have entire control of what is happening into you code, and where your code is writing. Do you know where is the pointer to "0" in your source?
How do you set up num? If it's really an array of characters rather than a string, there's no requirement that it be null terminated, unless it's a global/static. If you set it up like so in a function:
char str[10];
str[0] = '1';
str[1] = '0';
str[2] = '1';
than your strlen will get whatever, depending upon whatever junk happens to be in num.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//case 1: for num[9]="101";
char *extendBinary1(char num[], int len) {
int num_len = strlen(num);
memmove(num + (len - num_len), num, num_len);
memset(num, '0', (len - num_len));
return num;
}
//case 2: for "101";//pointer to const char
char *extendBinary2(const char num[], int len) {
int num_len = strlen(num);
char *number = calloc(len + 1, sizeof(char));
memset(number, '0', (len - num_len));
return strcat(number, num);
}
int main(void){
char num[9] = "101";
char *number = extendBinary2("101", 8);//dynamic allocate
printf("%s\n", extendBinary1(num, 8));
printf("%s\n", number);//free(number);
return 0;
}

Error with mystrlen function

I was trying to write out some of the implementations of the string functions available in C. My code is:
#include <stdio.h>
#include <stdlib.h>
char *mystrcpy(char *s1, char *s2)
{
while(*s1++ = *s2++);
return s1;
}
int mystrlen(char *s)
{
int len = 0;
while(*s != '\0')
{
len++;
}
return len;
}
int main(void)
{
char arr = "Hi";
char arr1[10];
char arr2[] = "Hello";
int length;
mystrcpy(arr1, arr2);
printf("%s", arr1);
length = mystrlen(arr);
printf("%d", length);
return 0;
}
mystrcpy works fine, but the other method mystrlen does no execute. What could be the error? The following is the program termination note:
Process terminated with status -1073741510 (0 minutes, 4 seconds)
Also, there are few warnings related to casts. Is there any place in the code where I should be using any cast?
First, your mystrlen has an infinite loop.
Fixed code:
int mystrlen(const char *s)
{
int len = 0;
while (*s++ /* increment to next character every loop */ != '\0')
{
len++;
}
return len;
}
Also added const since you never change the data referred to by *s
Second, the assignment: char arr="Hi"; is not valid.
You are attempting to assign a char[] array to a char variable. The correct form would be one of the following:
char arr[]="Hi"; // array syntax
char *arr="Hi"; // pointer syntax
Given your invalid arr assignment, your runtime error is most likely caused by mystrlen attempting to incorrectly deference arr.
What compiler are you using? Most conforming compilers should have caught the second issue. If using GCC, add the -Wall flag to your makefile.
This:
char arr="Hi"; /* Should have caused compiler warning,
as is attempting to assign a char
to a char[3]. */
should be:
char arr[] ="Hi";
or:
char* arr = "Hi";

Reversing a string in C using pointers?

Language: C
I am trying to program a C function which uses the header char *strrev2(const char *string) as part of interview preparation, the closest (working) solution is below, however I would like an implementation which does not include malloc... Is this possible? As it returns a character meaning if I use malloc, a free would have to be used within another function.
char *strrev2(const char *string){
int l=strlen(string);
char *r=malloc(l+1);
for(int j=0;j<l;j++){
r[j] = string[l-j-1];
}
r[l] = '\0';
return r;
}
[EDIT] I have already written implementations using a buffer and without the char. Thanks tho!
No - you need a malloc.
Other options are:
Modify the string in-place, but since you have a const char * and you aren't allowed to change the function signature, this is not possible here.
Add a parameter so that the user provides a buffer into which the result is written, but again this is not possible without changing the signature (or using globals, which is a really bad idea).
You may do it this way and let the caller responsible for freeing the memory. Or you can allow the caller to pass in an allocated char buffer, thus the allocation and the free are all done by caller:
void strrev2(const char *string, char* output)
{
// place the reversed string onto 'output' here
}
For caller:
char buffer[100];
char *input = "Hello World";
strrev2(input, buffer);
// the reversed string now in buffer
You could use a static char[1024]; (1024 is an example size), store all strings used in this buffer and return the memory address which contains each string. The following code snippet may contain bugs but will probably give you the idea.
#include <stdio.h>
#include <string.h>
char* strrev2(const char* str)
{
static char buffer[1024];
static int last_access; //Points to leftmost available byte;
//Check if buffer has enough place to store the new string
if( strlen(str) <= (1024 - last_access) )
{
char* return_address = &(buffer[last_access]);
int i;
//FixMe - Make me faster
for( i = 0; i < strlen(str) ; ++i )
{
buffer[last_access++] = str[strlen(str) - 1 - i];
}
buffer[last_access] = 0;
++last_access;
return return_address;
}else
{
return 0;
}
}
int main()
{
char* test1 = "This is a test String";
char* test2 = "George!";
puts(strrev2(test1));
puts(strrev2(test2));
return 0 ;
}
reverse string in place
char *reverse (char *str)
{
register char c, *begin, *end;
begin = end = str;
while (*end != '\0') end ++;
while (begin < --end)
{
c = *begin;
*begin++ = *end;
*end = c;
}
return str;
}

Resources