I just wrote my first program in C and it is a cesarean shift implementation. It works as expected with short inputs, but sometimes produces seemingly random bytes at the and of the output and I cannot figure out why.
I have tried looking at the program in GDB, but just don't have enough experience yet to figure out exactly what is going wrong. I would love to know how one would go about figuring this out with a debugger like GDB.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void rot(char*, int);
char alphabet[27] = "abcdefghijklmnopqrstuvwxyz";
int main (int argc, char* argv[]) {
if (argc != 3) {
printf("Usage: %s [lowercase-text] [rotation-number]\n", argv[0]);
return 1;
} else {
rot(argv[1], atoi(argv[2]));
}
}
void rot (char* t, int r) {
char result[100];
for (int i = 0; i < strlen(t); i++) {
char* location = strchr(alphabet, t[i]);
result[i] = location ? alphabet[(location - alphabet + r) % strlen(alphabet)] : t[i];
}
printf("%s\n", result);
}
Here is the unexpected output. The actual rotation works fine but there are some unexpected bytes at the end.
michael#linux:~/Desktop$ ./rotation
Usage: ./rotation [lowercase-text] [rotation-number]
michael#linux:~/Desktop$ ./rotation rotations_are_cool 13
ebgngvbaf_ner_pbby��� (<- Why are these here ???)
Here was my attempt with GDB. I have not been able to identify the extra data tagging at the end. (full output # https://pastebin.com/uhWnj17e)
(gdb) break *rot+260
Breakpoint 1 at 0x936: file ../rot.c, line 25.
(gdb) r rotations_are_cool 13
Starting program: /home/michael/Desktop/rotation rotations_are_cool 13
Breakpoint 1, 0x0000555555554936 in rot (
t=0x7fffffffe2d2 "rotations_are_cool", r=13) at ../rot.c:25
25 printf("%s\n", result);
(gdb) x/s $rbp-0x80
0x7fffffffdde0: "ebgngvbaf_ner_pbby\377\367\377\177"
This strange occurrence only happens around 50% of the time and happens more often with longer strings. Please help explain and eliminate this. Any other tips that would improve my code are also appreciated. Thanks a dozen!
The end of a string is recognized by the character '\0'.
So you could do it like this
char result[100];
int i;
for (i = 0; i < strlen(t); i++) {
char* location = strchr(alphabet, t[i]);
result[i] = location ? alphabet[(location - alphabet + r) % strlen(alphabet)] : t[i];
}
result[i] = '\0';
You also don't check, that result is large enough for the string, so you could allocate the needed memory dynamically
size_t len = strlen(t)
char *result = malloc(len + 1); /* +1 for terminating '\0' character */
if(result == NULL) {
/* Error allocating memory */
}
int i;
for (i = 0; i < len; i++) {
char* location = strchr(alphabet, t[i]);
result[i] = location ? alphabet[(location - alphabet + r) % strlen(alphabet)] : t[i];
}
result[i] = '\0';
printf("%s\n", result);
free(result);
Related
The instructions for this code wars problem is as follows:
link to the problem: https://www.codewars.com/kata/563b74ddd19a3ad462000054/train/c
"write me a function stringy that takes a size and returns a string of alternating '1s' and '0s'.
the string should start with a 1.
a string with size 6 should return :'101010'.
with size 4 should return : '1010'.
with size 12 should return : '101010101010'.
The size will always be positive and will only use whole numbers."
My solution to this problem is as follows.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char *stringy (size_t size)
{
char *s = malloc(sizeof(char) * size);
for(size_t i = 0; i < size ; i++)
{
if(i % 2 == 0)
{
memcpy(&s[i], "1", 1);
}
else
{
memcpy(&s[i], "0", 1);
}
}
return s;
}
This passes for numbers 12 and smaller but when they use larger numbers as size to test I will get extra 1's and 0's added to the end and will get an error like
for size = 41, expected:
"10101010101010101010101010101010101010101"
but got:
"1010101010101010101010101010101010101010101010101".
I've put this code into GitHub and made a variable that increments by one for every iteration of the for loop and used printf statements to print the variable just mentioned and the string of 0's and 1's and this works on GitHub with even larger numbers than 41 or anything they would test with on code wars. Is there something wrong with my code or with the test on code wars?
YOu need space for terminating NULL
And then you have to set the NULL at the end
char *stringy (size_t size)
{
char *s = malloc(sizeof(char) * (size+1)); <<<<========== +1
for( size_t i = 0; i < size ; i++)
{
if(i % 2 == 0)
{
memcpy(&s[i], "1", 1);
}
else
{
memcpy(&s[i], "0", 1);
}
}
s[size] = '\0'; <<<<=== trailing zero
return s;
}
as other have pointed out, memcpy is a huge overkill here, simpler (and less surprising to readers of the code) is
char *stringy (size_t size)
{
char *s = malloc(sizeof(char) * (size+1)); <<<<========== +1
for( size_t i = 0; i < size ; i++)
{
if(i % 2 == 0)
{
s[i] = '1';
}
else
{
s[i] = '0';
}
}
s[size] = '\0'; <<<<=== trailing zero
return s;
}
Note: I am not trying to get the algorithmic implementation! I already have it figured out in Java. I just can't seem to get my logic to work in C. Below is the Java code (which works) followed by the C99 code that breaks.
The high-level coding challenge that is presenting the segfault in my implementation is:
How to find all combinations of k length and smaller using alphabet of length n with repeating elements in C?
Problem
Code compiles, but I get a segmentation fault at runtime.
Notes / Observations
This is from a self-paced edX course I'm working my way through. I've already done the "less comfortable" challenges, and frankly they were a bit too easy. I'm now trying to go above the requirements and do this "more comfortable" (read more challenging) challenge. It is one of the more advanced beginner challenges.
I'm not a beginner programmer, but pretty much a novice with C.
As far as I understand it, the <cs50.h>is a custom header file that implements some things that simplify (read abstract away) command-line input and handling of strings. Documentation in it can be found at the cs50.net site and on the cs50lib GitHub page
I can't figure out the correct way to pass the values to the recursive function and need to utilize address referencing/dereferencing. Unfortunately my C is a bit fuzzy compared to other langs.
Test Calls with Desired Output Result
~/myTerminal $ ./printall ab 3
aaa
aab
aba
abb
baa
bab
bba
bbb
aa
ab
ba
bb
a
b
~/myTerminal $ ./printall abc 2
aa
ab
ac
ba
bb
bc
ca
cb
cc
a
b
c
myTerminal $ ./printall abcd 1
a
b
c
d
Java Code that Works
public class Main {
public static void main(String[] args) {
System.out.println("First Test");
char[] set1 = {'a', 'b'};
int k = 3;
printCombinations(set1, k);
System.out.println("\nSecond Test");
char[] set2 = {'a', 'b', 'c'};
k = 2;
printCombinations(set2, k);
System.out.println("\nThird Test");
char[] set3 = {'a', 'b', 'c', 'd'};
k = 1;
printCombinations(set3, k);
}
// Print all possible strings of length k or smaller.
static void printCombinations(char[] set, int k) {
int n = set.length;
for(int i = k; i > 0; i--)
{
printCombinationsRec(set, "", n, i);
}
}
// Print all combinations of length k
static void printCombinationsRec(char[] set, String prefix, int n, int k)
{
if (k == 0)
{ // Base case
System.out.println(prefix);
return;
}
// One by one add all characters
// from set and recursively
// call for k equals to k-1
for (int i = 0; i < n; ++i)
{
String newPrefix = prefix + set[i];
printCombinationsRec(set, newPrefix, n, k - 1);
}
}
}
C Code Causing Segmentation Fault
// CS50 custom header file
#include <cs50.h>
// "Regular" headers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void printCombinations();
void printCombinationsRecur();
int main(int argc, string argv[])
{
if (argc == 3) // Correct number of arguments
{
string strSet = argv[1];
int maxLength = atoi(argv[2]);
printCombinations(strSet, maxLength);
return 0;
}
// Incorrect usage
printf("Usage: %s <charset>:string\n <maxLength>:int\n", argv[0]);
return 1;
}
// Functions below were adapted and modified from code at :
// https://www.geeksforgeeks.org/print-all-combinations-of-given-length/
// Accessed : 2018-07-13
void printCombinations(string sSet, int strLength)
{
int aLength = strlen(sSet);
for (int i = strLength; i > 0; i--)
{
printCombinationsRecur(sSet, "", aLength, strLength);
}
}
void printCombinationsRecur(string *sSet, string prefix, int aLength, int strLength )
{
// printf("sSet: %s\nprefix: %s\naLength: %i\nstrLength: %i\n", *sSet, prefix, aLength, strLength);
// In terms of the traditional equation k=> strLength, n=>aLength, S=>sSet
if (strLength == 0)
{
printf("%s\n", prefix);
}
for (int i = 0; i < aLength; i++)
{
string temp1 = "";
strcat(temp1, prefix); // <== SEGFAULT HAPPENING HERE!
string newPrefix = strcat(temp1, sSet[i]);
printCombinationsRecur(sSet, newPrefix, aLength, strLength - 1);
}
}
I made the following change (suggested by #Stargateur) to the recursive function, but still get a segfault!
void printCombinationsRecur(string *sSet, string prefix, int aLength, int strLength )
{
// printf("sSet: %s\nprefix: %s\naLength: %i\nstrLength: %i\n", *sSet, prefix, aLength, strLength);
// In terms of the traditional equation k=> strLength, n=>aLength, S=>sSet
if (strLength == 0)
{
printf("%s\n", prefix);
}
for (int i = 0; i < aLength; i++)
{
printf("This prints");
char *temp1 = malloc((strLength +2) * sizeof(char));
for (int j = 0; j < strLength + 2; j++){
if(j < strLength)
{
temp1[j] = prefix[j];
}
if(j == strLength)
{
temp1[j] = *sSet[i];
}
if(j == strLength + 1){
temp1[j] = '\0';
}
}
printCombinationsRecur(sSet, temp1, aLength, strLength - 1);
free(temp1);
}
}
One of the key differences between your Java code that works and the C code that doesn't is in the printCombinations() function.
Working Java:
for(int i = k; i > 0; i--)
{
printCombinationsRec(set, "", n, i);
}
Broken C:
int aLength = strlen(sSet);
for (int i = strLength; i > 0; i--)
{
printCombinationsRecur(sSet, "", aLength, strLength);
}
You're calling the recursive function with the same length, over and over and over again. To match the Java, the strLength argument should be i instead.
You also do not handle the base case properly. The Java code returns after printing if k == 0; the C code doesn't.
Working Java:
if (k == 0)
{ // Base case
System.out.println(prefix);
return;
}
Broken C:
if (strLength == 0)
{
printf("%s\n", prefix);
}
And then you handle the string concatenation incorrectly. C is not very forgiving. There are at least two ways to handle it. The method that will work with any version of C uses malloc(). The method that will work with C99, or with C11 as long as the compiler does not define __STDC_NO_VLA__, uses a VLA. The version using malloc() also calls free() and so it does a bit more work than the other.
Since the length allocated is always the same, you could offset the cost by calling malloc() once before the loop and free() once after the loop, and you'd only need to copy the prefix once and then simply set the extra characters (even the null could be set once). You could also enhance the VLA code to define the new prefix array once outside the loop, copy the prefix once, set the null byte once, and just set the extra character inside the loop.
You should also use formal prototype declarations for the functions, not mere function declarations that care not one whit about the arguments presented.
The code shown below is lazy and does not check that the malloc() calls work. It also does not validate that the alphabet is a sensible length, nor that the maximum length is reasonable, nor that the elements in the alphabet are unique.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void printCombinations(const char *set, int strLength);
static void printCombinationsRec(const char *set, const char *prefix, int aLength, int strLength);
int main(int argc, char *argv[])
{
if (argc != 3)
{
fprintf(stderr, "Usage: %s alphabet maxlen\n", argv[0]);
return 1;
}
/* GIGO: garbage in, garbage out */
char *strSet = argv[1];
int maxLength = atoi(argv[2]);
printCombinations(strSet, maxLength);
return 0;
}
static void printCombinations(const char *set, int k)
{
int n = strlen(set);
for (int i = k; i > 0; i--)
{
printCombinationsRec(set, "", n, i);
}
}
#if defined(USE_VLA) && __STDC_NO_VLA__ != 1
static void printCombinationsRec(const char *set, const char *prefix, int n, int k)
{
if (k == 0)
{
printf("%s\n", prefix);
return;
}
for (int i = 0; i < n; ++i)
{
size_t len = strlen(prefix);
char newPrefix[len + 2];
strcpy(newPrefix, prefix);
newPrefix[len + 0] = set[i];
newPrefix[len + 1] = '\0';
printCombinationsRec(set, newPrefix, n, k - 1);
}
}
#else
static void printCombinationsRec(const char *set, const char *prefix, int n, int k)
{
if (k == 0)
{
printf("%s\n", prefix);
return;
}
for (int i = 0; i < n; ++i)
{
size_t len = strlen(prefix);
char *newPrefix = malloc(len + 2);
strcpy(newPrefix, prefix);
newPrefix[len + 0] = set[i];
newPrefix[len + 1] = '\0';
printCombinationsRec(set, newPrefix, n, k - 1);
free(newPrefix);
}
}
#endif /* USE_VLA */
Compiled with -DUSE_VLA with a compiler that supports VLAs, it will not use malloc(). Compiled without the option, or with a compiler that supports C11 but does not support VLAs, then it uses malloc() and free().
At one point, I also added argument validation code in main(), but the 20 lines or so seemed to be more getting in the way than useful, so I left the GIGO comment there instead.
If this was 'production code', I'd be using error reporting functions and would not skip the checks (in part because the error reporting functions make it easier, using a single line per reported error instead of 5 or so without. I'd be using the error reporting code available in my SOQ (Stack Overflow Questions) repository on GitHub as files stderr.c and stderr.h in the src/libsoq sub-directory.
Note that you can't use strcat() easily because you want to append a single character, not a string. Hence the use of the two assignments. The + 0 emphasizes the similarity between the two assignments; the compiler does not generate any code for + 0.
When run (I called it comb47.c, compiled to comb47), it produces the output desired:
$ comb47 ab 3
aaa
aab
aba
abb
baa
bab
bba
bbb
aa
ab
ba
bb
a
b
$ comb47 abc 2
aa
ab
ac
ba
bb
bc
ca
cb
cc
a
b
c
$ comb47 abcd 1
a
b
c
d
$
I've spent last night debugging this little piece of code. I have two data text files, both contain 18000 chars. Id like to split these 18000 into two sub-strings each of 100 chars, that makes 180 iterations.
The tricky thing is, in the first 180 iterations the size of both sub-strings is fine. After 18 iterations, the sizes of the sub-strings are 0.
Both files were opened properly. I can print them and so on. I tried to allocate the sub-strings in all the possible ways I could think of but could find no solution so far.
int main(int argc, char const *argv[]) {
//Ive loaded two files into two strings buff1 and buff2 both size of 18000 chars
//It works fine with small data example, I dunno why but eventually I have work with much more bigger data set
//Id like to divide them into 100 char long pieces and do some stuff with that
char *substrA; //substring for buff1
char *substrB; //substring for buff2
substrA = malloc((wlen+1)*sizeof(char)); //word length wlen=100
substrA = malloc((wlen+1)*sizeof(char));
for (int i= 0; i <numOfSubProblems; ++i){ //numOfSubProblems = 18000/100
strncpy(substrA, buff1+i*wlen, wlen);
strncpy(substrB, buff2+i*wlen, wlen);
substrA[wlen] = '\0';
substrA[wlen] = '\0';
int lenA = strlen(substrA);
int lenB = strlen(substrB);
printf("STRA a STR B: %d %d \n",lenA,lenB);
DoSomething(substrA,substrB,i); //some parser and other functionality
}
return 0;
}
strncpy does not null-terminate the destination string. So you have to do
strncpy(subA, buff1+i*wlen, wlen);
subA[wlen] = '\0';
strncpy(subB, buff2+i*wlen, wlen);
subB[wlen] = '\0';
Otherwise you cannot use strlen, and you access the buffers behind their end when doing so.
Use snprintf.
You may not be dealing with formatting strings, but at least it is a sane API. Also make sure to round up when determining the number of subproblems:
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#define PROBSIZE 18002
int main (int argc, char **argv) {
char input[PROBSIZE];
for (size_t i = 0; i < PROBSIZE; ++i) {
input[i] = 'A' + (i % 10);
}
const size_t wlen = 10;
char *subA = malloc (wlen + 1);
if (!subA) {
return EXIT_FAILURE;
}
for (int i = 0; i < (PROBSIZE + wlen - 1) / wlen; ++i) {
/* If there's no error, guarantees `wlen` characters copied */
int err = snprintf(subA, wlen + 1, "%s", input + i * wlen);
if (err < 0) {
fprintf(stderr, "snprintf encountered an error\n");
return EXIT_FAILURE;
}
/* In absence of errors, we expect that the return value is
* always >= wlen + 1, except the last iteration.
*/
assert(err >= wlen + 1 || i == ((PROBSIZE + wlen - 1) / wlen) - 1);
printf("%s\n", subA);
}
return EXIT_SUCCESS;
}
I have a CGI application I've been writing in Visual Studio Express 2013, but I've encountered a scenario where the program fails when the string passed into a function is more than 31 bytes. I would try to debug it myself, but everything works fine in Visual Studio Debugger, it's only in Command Prompt where I see the error.
I believe this to be the way that I've allocated(or not allocated) the memory. I have a function which takes in a string and returns the decoded string.
I've stripped everything down to just that function and main so you can see two cases, one which works in CMD and one which fails.
Here's the file:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* Function: urlDecode
* Purpose: Decodes a web-encoded URL
* Input: const char* str - the URL to decode
* Output: char* - the decoded URL
*/
char *urlDecode(const char *str) {
int d = 0; /* whether or not the string is decoded */
char *dStr = malloc(strlen(str) + 1);
char *eStr = malloc(2); /* a hex code */
strcpy(dStr, str);
while (!d) {
d = 1;
int i; /* the counter for the string */
int j = strlen(dStr);
for (i = 0; i<j; ++i) {
if (dStr[i] == '%') {
if (dStr[i + 1] == 0)
return dStr;
if (isxdigit(dStr[i + 1]) && isxdigit(dStr[i + 2])) {
d = 0;
//combine the next two numbers into one
eStr[0] = dStr[i + 1];
eStr[1] = dStr[i + 2];
//convert it to decimal
long int x = strtol(eStr, NULL, 16);
//remove the hex
memmove(&dStr[i], &dStr[i + 2], strlen(dStr) - 1);
dStr[i] = x;
j = j - 2;
}
}
}
}
free(eStr);
return dStr;
}
int main(void)
{
//this one runs fine from command prompt
char *test1 = "s=W3%20%3A%20SVC&action=stop";
printf("%s\n", test1);
char *decoded1 = urlDecode(test1);
printf("%s\n", decoded1);
free(decoded1); //and I can even free the memory
//this one prints in command prompt, but the program crashes immediately after
char *test2 = "service=W3%20%3A%20SVC&action=stop";
printf("%s\n", test2);
char *decoded2 = urlDecode(test2);
printf("%s\n", decoded2);
//when I comment this free out, it debugs fine in VS, but still fails in cmd
//this is the reason I believe it's a memory error
//free(decoded2);
system("PAUSE"); //so I can see what's happening
return 0;
}
You failed to null-terminate eStr, and you did not allocate enough memory for it: you need three characters, not two.
Since eStr is so short, consider making it a stack variable, rather than allocating it on the dynamic store:
char eStr[] = "00";
This would allocate enough space, and make it unnecessary to free the pointer at the end of your function.
Another issue is memmove: it looks like your indexes are off. You could fix it, but it's much easier to avoid memmove altogether: rather than making substitutions in place, use str as your source, and dStr as your destination:
char *urlDecode(const char *str) {
int d = 0; /* whether or not the string is decoded */
char *dStr = malloc(strlen(str) + 1);
char *ret = dStr;
char eStr[] = "00";
strcpy(dStr, str);
while (!d) {
d = 1;
int i; /* the counter for the string */
int j = strlen(dStr);
for (i = 0; i<j; ++i) {
if (str[i] == '%') {
if (str[i + 1] == 0) {
break;
}
if (isxdigit(str[i + 1]) && isxdigit(str[i + 2])) {
d = 0;
//combine the next two numbers into one
eStr[0] = str[i + 1];
eStr[1] = str[i + 2];
//convert it to decimal
long int x = strtol(eStr, NULL, 16);
*dStr++ = x;
}
} else {
*dStr++ = str[i];
}
}
}
*dStr = 0;
return ret;
}
Demo.
should be
char *eStr = calloc(3,1); /* a hex code */
memmove(&dStr[i+1], &dStr[i + 3], strlen(&dStr[i+3])+1 );
I can't write a workable code for a function that deletes N characters from the string S, starting from position P. How you guys would you write such a function?
void remove_substring(char *s, int p, int n) {
int i;
if(n == 0) {
printf("%s", s);
}
for (i = 0; i < p - 1; i++) {
printf("%c", s[i]);
}
for (i = strlen(s) - n; i < strlen(s); i++) {
printf("%c", s[i]);
}
}
Example:
s: "abcdefghi"
p: 4
n: 3
output:
abcghi
But for a case like n = 0 and p = 1 it's not working!
Thanks a lot!
A few people have shown you how to do this, but most of their solutions are highly condensed, use standard library functions or simply don't explain what's going on. Here's a version that includes not only some very basic error checking but some explanation of what's happening:
void remove_substr(char *s, size_t p, size_t n)
{
// p is 1-indexed for some reason... adjust it.
p--;
// ensure that we're not being asked to access
// memory past the current end of the string.
// Note that if p is already past the end of
// string then p + n will, necessarily, also be
// past the end of the string so this one check
// is sufficient.
if(p + n >= strlen(s))
return;
// Offset n to account for the data we will be
// skipping.
n += p;
// We copy one character at a time until we
// find the end-of-string character
while(s[n] != 0)
s[p++] = s[n++];
// And make sure our string is properly terminated.
s[p] = 0;
}
One caveat to watch out for: please don't call this function like this:
remove_substr("abcdefghi", 4, 3);
Or like this:
char *s = "abcdefghi";
remove_substr(s, 4, 3);
Doing so will result in undefined behavior, as string literals are read-only and modifying them is not allowed by the standard.
Strictly speaking, you didn't implement a removal of a substring: your code prints the original string with a range of characters removed.
Another thing to note is that according to your example, the index p is one-based, not zero-based like it is in C. Otherwise the output for "abcdefghi", 4, 3 would have been "abcdhi", not "abcghi".
With this in mind, let's make some changes. First, your math is a little off: the last loop should look like this:
for (i = p+n-1; i < strlen(s); i++) {
printf("%c", s[i]);
}
Demo on ideone.
If you would like to use C's zero-based indexing scheme, change your loops as follows:
for (i = 0; i < p; i++) {
printf("%c", s[i]);
}
for (i = p+n; i < strlen(s); i++) {
printf("%c", s[i]);
}
In addition, you should return from the if at the top, or add an else:
if(n == 0) {
printf("%s", s);
return;
}
or
if(n == 0) {
printf("%s", s);
} else {
// The rest of your code here
...
}
or remove the if altogether: it's only an optimization, your code is going to work fine without it, too.
Currently, you code would print the original string twice when n is 0.
If you would like to make your code remove the substring and return a result, you need to allocate the result, and replace printing with copying, like this:
char *remove_substring(char *s, int p, int n) {
// You need to do some checking before calling malloc
if (n == 0) return s;
size_t len = strlen(s);
if (n < 0 || p < 0 || p+n > len) return NULL;
size_t rlen = len-n+1;
char *res = malloc(rlen);
if (res == NULL) return NULL;
char *pt = res;
// Now let's use the two familiar loops,
// except printf("%c"...) will be replaced with *p++ = ...
for (int i = 0; i < p; i++) {
*pt++ = s[i];
}
for (int i = p+n; i < strlen(s); i++) {
*pt++ = s[i];
}
*pt='\0';
return res;
}
Note that this new version of your code returns dynamically allocated memory, which needs to be freed after use.
Here is a demo of this modified version on ideone.
Try copying the first part of the string, then the second
char result[10];
const char input[] = "abcdefg";
int n = 3;
int p = 4;
strncpy(result, input, p);
strncpy(result+p, input+p+n, length(input)-p-n);
printf("%s", result);
If you are looking to do this without the use of functions like strcpy or strncpy (which I see you said in a comment) then use a similar approach to how strcpy (or at least one possible variant) works under the hood:
void strnewcpy(char *dest, char *origin, int n, int p) {
while(p-- && *dest++ = *origin++)
;
origin += n;
while(*dest++ = *origin++)
;
}
metacode:
allocate a buffer for the destination
decalre a pointer s to your source string
advance the pointer "p-1" positions in your source string and copy them on the fly to destination
advance "n" positions
copy rest to destination
What did you try? Doesn't strcpy(s+p, s+p+n) work?
Edit: Fixed to not rely on undefined behaviour in strcpy:
void remove_substring(char *s, int p, int n)
{
p--; // 1 indexed - why?
memmove(s+p, s+p+n, strlen(s) - n);
}
If your heart's really set on it, you can also replace the memmove call with a loop:
char *dst = s + p;
char *src = s + p + n;
for (int i = 0; i < strlen(s) - n; i++)
*dst++ = *src++;
And if you do that, you can strip out the strlen call, too:
while ((*dst++ = *src++) != '\0);
But I'm not sure I recommend compressing it that much.